[HNOI2008]玩具装箱TOY
题目描述
P教授要去看奥运,但是他舍不下他的玩具,于是他决定把所有的玩具运到北京。他使用自己的压缩器进行压缩,其可以将任意物品变成一堆,再放到一种特殊的一维容器中。P教授有编号为1...N的N件玩具,第i件玩具经过压缩后变成一维长度为Ci.为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时如果一个一维容器中有多个玩具,那么两件玩具之间要加入一个单位长度的填充物,形式地说如果将第i件玩具到第j个玩具放到一个容器中,那么容器的长度将为 x=j-i+Sigma(Ck) i<=K<=j 制作容器的费用与容器的长度有关,根据教授研究,如果容器长度为x,其制作费用为(X-L)^2.其中L是一个常量。P教授不关心容器的数目,他可以制作出任意长度的容器,甚至超过L。但他希望费用最小.
输入输出格式
输入格式:第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
输出格式:输出最小费用
输入输出样例
输入样例#1:
5 4 3 4 2 1 4
输出样例#1:
1
dp方程:
f[i]=f[j]+(i-j-1+s[i]-s[j]-l)^2
=>f[j]+((i+s[i]-1-l)-(j+s[j]))^2
=>f[j]+(i+s[i]-1-l)^2+(j+s[j])^2-2(i+s[i]-1-l)*(j+s[j])
然后就可以斜率优化
对于i,j比k优时有:j>=k
f[j]+(i+s[i]-1-l)^2+(j+s[j])^2-2(i+s[i]-1-l)*(j+s[j])
<=f[k]+(i+s[i]-1-l)^2+(k+s[k])^2-2(i+s[i]-1-l)*(k+s[k])
=>(f[j]+(j+s[j])^2-f[k]-(k+s[k])^2)/2*(j+s[j]-k-s[k])<=(i+s[i]-1-l)
公式只有右边与i有关,考虑用单调队列,令
yj=f[j]+(j+s[j])^2,xj=(j+s[j])
原式=>(yj-yk)/(xj-xk)<=(i+s[i]-1-l)
令g[k,j]=原式
首先,不等式成立说明j优于k,由于右边单调递增,所以j以后都优于k,丢掉k
其次,k<j<i&&g[j,i]<g[k,j]则j可以丢掉
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 typedef long long lol; 7 lol l,n,sum[100001]; 8 int head,tail; 9 lol s[100001],f[100001]; 10 lol X(lol x) 11 { 12 lol fm=x+sum[x]; 13 return 2*fm; 14 } 15 lol Y(lol x) 16 { 17 lol fz=f[x]+(x+sum[x])*(x+sum[x]); 18 return fz; 19 } 20 int main() 21 {lol i; 22 cin>>n>>l; 23 for (i=1;i<=n;i++) 24 { 25 scanf("%lld",&sum[i]); 26 sum[i]+=sum[i-1]; 27 } 28 head=1;tail=1; 29 s[1]=0; 30 for (i=1;i<=n;i++) 31 {lol j=0; 32 while (head+1<=tail&&(X(s[head+1])-X(s[head]))*(i+sum[i]-l-1)>=Y(s[head+1])-Y(s[head])) head++; 33 j=s[head]; 34 //cout<<head<<' '<<tail<<endl; 35 f[i]=f[j]+(i-j-1+sum[i]-sum[j]-l)*(i-j-1+sum[i]-sum[j]-l); 36 while (tail-1>=head&&(Y(s[tail])-Y(s[tail-1]))*(X(i)-X(s[tail]))>=(X(s[tail])-X(s[tail-1]))*(Y(i)-Y(s[tail]))) tail--; 37 tail++; 38 s[tail]=i; 39 //cout<<j<<endl; 40 } 41 cout<<f[n]; 42 }