ZJOI 仓库建设 (斜率DP)

f[i]=min(f[j]+w[j,i])+c[i];  j∈[0,i-1]

w[j,i]=p[j+1]*(x[i]-x[j+1])+...+p[i]*(x[i]-x[i]);

最裸的DP是n^2的,显然会超时

现在化简一下w[j,i]

w[j,i]=x[i]*(p[j+1]+...+p[i])-(x[j+1]*p[j+1]+...+x[i]*p[i]);

设sum[i]=sigma(p[j]*x[j]);  sump[i]=sigma(p[j]);   j∈[1,i]

那么 w[j,i]=-x[i]*(sump[i]-sump[j])-(sum[i]-sum[j])

       =-x[i]*sump[j]+sum[j]+x[i]*sump[i]-sum[i];

即 f[i]=min(-x[i]*sump[j]+sum[j]+f[j])+x[i]*sum[i]-sum[i];   j∈[0,i-1]

注意到sump[j] 和 sum[j]+f[j] 是单调递增的,可以证明决策是单调向右的。

维护一个下凸包即可。

附 DP斜率优化参考教程

①:http://wenku.baidu.com/link?url=9JNX3KG-XtAljlg1JDOIvSN_t_UntKNFdi-mDgWOh-oUEIbFQDOStyKRKXxUILxZ1CQXBJNoPzKf23IHmLtNT65peiiBoxl9vDM-G6MPsJy

②:http://www.cnblogs.com/ka200812/archive/2012/08/03/2621345.html

 1 const maxn=1000008;
 2 var q,f,x,p,c,sum,sump:array[0..maxn] of int64;
 3     i,h,t,n:longint;
 4 function kx(i,j:longint):int64;
 5 begin
 6     exit(sump[i]-sump[j]);
 7 end;
 8 function ky(i,j:longint):int64;
 9 begin
10     exit(f[i]+sum[i]-f[j]-sum[j]);
11 end;
12 begin
13     readln(n);
14     for i:=1 to n do readln(x[i],p[i],c[i]);
15     for i:=1 to n do sump[i]:=sump[i-1]+p[i];
16     for i:=1 to n do sum[i]:=sum[i-1]+p[i]*x[i];
17     q[1]:=0; h:=1; t:=1;
18     for i:=1 to n do 
19     begin
20         while (h<t) and (x[i]*kx(q[h+1],q[h])>ky(q[h+1],q[h])) do inc(h);
21         f[i]:=-x[i]*sump[q[h]]+f[q[h]]+sum[q[h]]+x[i]*sump[i]-sum[i]+c[i];
22         while (h<t) and ( ky(i,q[t])*kx(q[t],q[t-1])<=ky(q[t],q[t-1])*kx(i,q[t])) do dec(t);
23         inc(t);
24         q[t]:=i;    
25     end;
26     writeln(f[n]);
27 end.

 

posted @ 2015-01-14 15:26  rpSebastian  阅读(272)  评论(0编辑  收藏  举报