APIO2010 特别行动队
题目不在累述,在RQNOJ或八中上都有。
朴素方程很好写
f[i]=max{f[j]+a*sqr(s[i]-s[j])+b*(s[i]-s[j])+c}
典型的1D/1D方程,有数据范围来看,一定有O(n)算法,于是模式基本就确定下来了,我们要对方程进行变形。
设对于f[i]决策x优于y且x<y
则:f[x]+a*(s[i]-s[x])*(s[i]-s[x])+b*(s[i]-s[x])+c>f[y]+a*(s[i]-s[y])*(s[i]-s[y])+b*(s[i]-s[y])+c
→f[x]+a*s[i]*s[i]-2*a*s[i]*s[x]+a*s[x]*s[x]+b*s[i]-b*s[x]+c>f[y]+a*s[i]*s[i]-2*a*s[i]*s[y]+a*s[y]*s[y]+b*s[i]-b*s[y]+c
→f[x]-2*a*s[i]*s[x]+a*s[x]*s[x]-b*s[x]>f[y]-2*a*s[i]*s[y]+a*s[y]*s[y]-b*s[y]
我们令g[i]=f[i]+a*s[i]*s[i]-b*s[i]
则有g[x]-2*a*s[i]*s[x]>g[y]-2*a*s[i]*s[y]
→g[x]-g[y]>2*a*s[i]*(s[x]-s[y])
由于x<y且每一个战斗力均为正,所以s[x]-s[y]<0
所以(g[x]-g[y])/(s[x]-s[y])<2*a*s[i]
左边的式子是什么?两点连线的斜率啊!由以上式子,我们可以得到
对于当前状态i,如果最优状态为p,那么对于j1<p 有 k(j1,p)>=2*a*s[i]
对于p<j2 有 k(p,j2)<2*a*s[i]
满足单调型!!!!!!
相当与维护一个平面上的点集(s[i],g[i])凸包,每次决策也一定单调,这就让我们用一个队列来维护这个凸包,每个决策最多入队出队各一次,平摊时间复杂度为O(n)
问题完美解决,特别的队列中有一个点时,它就是当前决策最优点。
1 program APIO(input,output); 2 var 3 f,g :array[0..1000050] of int64; 4 s :array[0..1000050] of longint; 5 q :array[0..1000050] of longint; 6 a,b,c :longint; 7 n :longint; 8 procedure init; 9 var 10 i:longint; 11 begin 12 readln(n); 13 readln(a,b,c); 14 s[0]:=0; 15 for i:=1 to n do 16 begin 17 read(s[i]); 18 s[i]:=s[i]+s[i-1]; 19 end; 20 end;{ init } 21 function K(x,y:longint):double; 22 begin 23 exit(double(g[y]-g[x])/double(s[y]-s[x])); 24 end; { K } 25 procedure main; 26 var 27 i :longint; 28 head,tail:longint; 29 bestK :double; 30 begin 31 f[0]:=0; 32 head:=1; 33 tail:=1; 34 q[1]:=0; 35 for i:=1 to n do 36 begin 37 bestK:=double(2*a*s[i]); 38 while (tail-head+1>1)and(K(q[head],q[head+1])>=bestK) do 39 inc(head); 40 f[i]:=int64(f[q[head]])+int64(a)*int64(s[i]-s[q[head]])*int64(s[i]-s[q[head]])+int64(b)*int64(s[i]-s[q[head]])+int64(c); 41 g[i]:=int64(f[i])+int64(a)*int64(s[i])*int64(s[i])-int64(b)*int64(s[i]); 42 while (tail-head+1>=2)and(K(q[tail],i)>K(q[tail-1],q[tail])) do 43 dec(tail); 44 inc(tail); 45 q[tail]:=i; 46 end; 47 end; 48 procedure print; 49 begin 50 writeln(f[n]); 51 end; 52 begin 53 init; 54 main; 55 print; 56 end.