好题,我们先来考虑第i关,要能打死所有僵尸的攻击力得要满足什么条件
我们设排头的是第i个僵尸,植物这关攻击力为yi
不难得到对于第j个僵尸,植物开始打到他时,他离房子的距离为xi+(i-j)*d-(sum[i]-sum[j])/yi
(sum[]表示僵尸的血量前缀和)
也就是aj/yi<=xi+(i-j)*d-(sum[i]-sum[j])/yi,整理可得
yi>=(sum[i]-sum[j-1])/(xi+(i-j)*d)
也就是我们要求yi=max(sum[i]-sum[j-1])/(xi+(i-j)*d))看到这个立马想到斜率优化
我们把(sum[j-1],j*d)看作一个状态点,也就是问一个点(sum[i],xi+i*d)和前面点斜率的最大值
注意状态点坐标都是单调的,画图不难发现上凸的点是没有意义的,我们要维护一个下凸线
对于询问,我们发现和状态点构成的斜率是单调的,因此我们可以用三分来求
注意这里的三分是整数的三分,要小心
1 type node=record 2 x,y:int64; 3 end; 4 5 var i,n,t:longint; 6 d,h,x:int64; 7 s:array[0..100010] of int64; 8 q:array[0..100010] of longint; 9 a:array[0..100010] of node; 10 now:node; 11 ans:double; 12 function getk(i,j:longint):double; 13 begin 14 exit((a[j].y-a[i].y)/(a[j].x-a[i].x)); 15 end; 16 17 function max(a,b:double):double; 18 begin 19 if a>b then exit(a) else exit(b); 20 end; 21 22 function calc(j:longint):double; 23 begin 24 exit((now.y-a[j].y)/(now.x-a[j].x)); 25 end; 26 27 function ask:double; 28 var l,r,m:longint; 29 begin 30 l:=1; 31 r:=t; 32 while l+1<r do 33 begin 34 m:=(r-l+1) div 3; 35 if calc(q[l+m])<calc(q[l+2*m]) then l:=l+m+1 36 else r:=l+2*m-1; 37 end; 38 exit(max(calc(q[l]),calc(q[r]))); 39 end; 40 41 begin 42 readln(n,d); 43 for i:=1 to n do 44 begin 45 readln(h,x); 46 s[i]:=s[i-1]+h; 47 a[i].x:=int64(i)*d; a[i].y:=s[i-1]; 48 now.x:=x+a[i].x; now.y:=s[i]; 49 while (t>1) and (getk(q[t-1],q[t])>getk(q[t],i)) do dec(t); 50 inc(t); 51 q[t]:=i; 52 ans:=ans+ask; 53 end; 54 writeln(ans:0:0); 55 end.