斜率优化dp
据说这题朴素的O(n2)dp也可以A 没试过
朴素的dp不难想:f[i]=min(f[j]+sumtime[i]*sumcost[j+1,i]+c*sumcost[j+1,n]) 稍微解释一下,当选择j+1~i为同一批任务的时候
j+1~n的任务都要额外花费开机的时间
复杂度是O(n2),有没有更好的方法呢?
我们用t[i]表示前i个任务的总时间,w[i]表示前i个任务的总费用;
方程式即为f[i]=min(f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j]));
对于当前阶段i,考虑两个决策j,k, 假定k>j
当决策k优于决策j时,即f[k]+t[i]*(w[i]-w[k])+c*(w[n]-w[k])<=f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j])
将常数都放在一边,整理可得
(t[i]+c)(w[k]-w[j])/(f[k]-f[j])>=1
显然f是单调增的,对于两个决策k,j,只要满足这个条件,k就一定优于j
我们考虑将左边设为决策G(k,j);
对于k<j<i
当G(i,j)>G(j,k) j一定不是最优
1 当G(i,j)>=1 时 显然i比j优
2 当G(i,j)<1 时 则G(j,k)<1则 k比j优
所以j可以被舍去
这样我们可以通过单调队列来维护 复杂度O(n)
1 var f,t,w:array[0..10010] of int64; 2 q:array[0..10010] of longint; 3 h,c,i,j,n,r:longint; 4 function top(k,j:longint):int64; 5 begin 6 exit(w[k]-w[j]); 7 end; 8 9 function down(k,j:longint):int64; 10 begin 11 exit(f[k]-f[j]); 12 end; 13 14 begin 15 readln(n); 16 readln(c); 17 for i:=1 to n do 18 readln(t[i],w[i]); 19 for i:=1 to n do 20 begin 21 t[i]:=t[i]+t[i-1]; 22 w[i]:=w[i]+w[i-1]; 23 end; 24 h:=0; 25 r:=0; 26 f[0]:=0; 27 for i:=1 to n do 28 begin 29 while (h<r) and ((t[i]+c)*top(q[h+1],q[h])>=down(q[h+1],q[h])) do inc(h); //这里最好写成除法表示 30 j:=q[h]; 31 f[i]:=f[j]+t[i]*(w[i]-w[j])+c*(w[n]-w[j]); 32 while (h<r) and (top(i,q[r])*down(q[r],q[r-1])>=top(q[r],q[r-1])*down(i,q[r])) do dec(r); 33 inc(r); 34 q[r]:=i; 35 end; 36 writeln(f[n]); 37 end.