bzoj3203

好题,我们先来考虑第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.
View Code
原文地址:https://www.cnblogs.com/phile/p/4472936.html