Best Cow Fences(poj2018)
Best Cow Fences(poj2018)
【问题描述】
题意很简单,就是给你n个数,求一个连续数串的平均值最大,数串长度不小于F
n<=100000
【分析】
在不考虑数据范围的情况下,可以很容易地写出O(n^2)的动规方程,f[i]=max{(sum[i]-sum[j-1])/(i-j+1)}
如果我们把sum的图像画出来,那么我们发现这就是过点Si和Sj-1的直线的斜率!
也就是问题转化成在求平面上任意两点斜率的最大值。这时候我们只要维护一个下凸折线就可以了。对于一个点i,显然它与折线相切时斜率最大。这个可以自己手动画个图看看。
我们可以用单调队列的算法来维护下凸折线,又由于折线上过每一个点切线的斜率都是一定的,而且根据下凸函数斜率的单调性,决策是单调的,保留一个指针不回溯的向后移动以寻找切线斜率即可,平摊复杂度为O(1)。
【代码】
var i,j,n,m,k,l,h,t:longint;
q:array[0..100000]of longint;
sum:array[0..100000]of longint;
ans:extended;
function slope(i,j:Longint):extended;
begin
exit((sum[i]-sum[j])/(i-j));
end;
begin
assign(input,'maxaverage.in');reset(input);
assign(output,'maxaverage.out');rewrite(output);
readln(n,m);
sum[0]:=0;
for i:=1 to n do
begin
read(k);
sum[i]:=sum[i-1]+k;
end;
h:=1;t:=1;q[1]:=0;ans:=0;
for i:=m to n do
begin
while (h<>t)and(slope(i,q[h])<slope(i,q[h+1])) do inc(h);
if ans<slope(i,q[h]) then ans:=slope(i,q[h]);
j:=i-m+1;
while (h<>t)and(slope(q[t],q[t-1])>slope(q[t],j)) do dec(t);
inc(t);q[t]:=j;
end;
writeln(trunc(ans*1000));
close(input);close(output);
end.