POJ2018 Best Cow Fences——二分答案+贪心(动态规划)求最大子段和——pku2018

可以转换成二分答案求最大连续子段和来做。

每次在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.

你可能感兴趣的:(动态规划)