可以转换成二分答案求最大连续子段和来做。
每次在a[i]的基础上减去二分出来的答案。
求出长度不小于f的最大连续子段和。如果大于0,则调整下边界,否则调整上边界。
求长度不小于f的最大连续子段和需要一些小技巧,比如说判断以i为终点的连续子段和,就可以看sum[i]-sum[i-f]+dp[i-f]的正负。其中dp[i]表以i为终点的最大连续子段和。具体见代码。
Program cowfnc;//By_Thispoet Const maxn=100005; Var i,j,k,m,n,f,ans :Longint; l,r,mid :Longint; a,dp,sum,b :Array[0..maxn]of Int64; Function Max(i,j:Longint):Longint; begin if i>j then exit(i);exit(j); end; Function Check(i:Longint):Boolean; var j,k:Longint; begin for j:=1 to n do b[j]:=a[j]-i; for j:=1 to n do dp[j]:=Max(0,dp[j-1]+b[j-1]); for j:=1 to n do sum[j]:=sum[j-1]+b[j]; for j:=1 to n-f+1 do if sum[j+f-1]-sum[j-1]+dp[j]>=0 then exit(true); exit(false); end; BEGIN readln(n,f); r:=0; for i:=1 to n do begin readln(a[i]); a[i]:=a[i]*1000; r:=Max(r,a[i]); end; l:=0; while l<=r do begin mid:=(l+r)>>1; if check(mid) then begin ans:=mid; l:=mid+1; end else r:=mid-1; end; writeln(ans); END.