高考结束后,同学们大都找到了一份临时工作,渴望挣得一些零用钱。从今天起,Matrix67将连续工作N天(1<=N<=100 000)。每一天末他可以领取当天及前面若干天里没有领取的工资,但他总共只有M(1<=M<=N)次领取工资的机会。Matrix67已经知道了在接下来的这N天里每一天他可以赚多少钱。为了避免自己滥用零花钱,他希望知道如何安排领取工资的时间才能使得领到工资最多的那一次工资数额最小。注意Matrix67必须恰好领工资M次,且需要将所有的工资全部领走(即最后一天末需要领一次工资)。
这个题目让我想起了最近有个测试题目——复制书稿。当时写了个O(n^3)的DP,结果被题目给的数据范围坑掉了……尼玛明明给的n<=100结果尼玛给了6个n=1000的点……(吐槽结束,入正题)
正如那道题一样,如果想要过这道题目DP是会TLE的~所以需要二分答案。二分领到工资的最大值,然后判断是否可行,并继续二分。
判断是否可行只需要贪心。
[pascal 代码]
VAR
L,R,MID,N,M,I:LONGINT;
A,B:ARRAY[1..100000]OF LONGINT;
FUNCTION CHECK(P:LONGINT):BOOLEAN;
VAR
I,PRE,TOT:LONGINT;
BEGIN
TOT:=M;
PRE:=0;
I:=1;
WHILE I<=N DO
BEGIN
IF PRE+A[I]<=P THEN
BEGIN
PRE:=PRE+A[I];
INC(I);
END
ELSE
BEGIN
PRE:=0;
DEC(TOT);
IF TOT=0 THEN EXIT(FALSE);
END;
END;
EXIT(TRUE);
END;
BEGIN
READLN(N,M);
R:=0;
FOR I:=1 TO N DO
BEGIN
READLN(A[I]);
INC(R,A[I]);
END;
L:=0;
WHILE L<R DO
BEGIN
MID:=(L+R)>>1;
IF CHECK(MID) THEN R:=MID ELSE L:=MID+1;
END;
WRITELN(L);
END.