首页 > 代码库 > 【BZOJ1010】【HNOI2008】玩具装箱

【BZOJ1010】【HNOI2008】玩具装箱

继续看黄学长代码技术分享

原题:

 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

 

会DP的都能想出的状态转移方程:f[i]=min(f[j]+(sum[i]-sum[j]+i-j-1-l)^2)

然后可以发现有些东西是怎么都不会变得,可以让s[i]=sum[i]+i,c=l+1

呢么这个方程就变成f[i]=min(f[j]+(s[i]-s[j]-c)^2)

然后就搞斜率优化

假设在i阶段有个一个优于j的决策k,呢么f[k]+(s[i]-s[k]-c)^2<=f[j]+(s[i]-s[j]-c)^2

呢么想要证明对于i后的所有状态t,要证明决策单调性,就是f[k]+(s[t]-s[k]-c)^2<=f[j]+(s[t]-s[j]-c)^2

因为s是固定的,所以s[t]可以表示为s[i]+v

f[k]+(s[i]+v-s[k]-c)^2<=f[j]+(s[i]+v-s[j]-c)^2

f[k]+ (s[i]-s[k]-c)^2 + 2*v*(s[i]-s[k]-c) + v^2 <= f[j]+ (s[i]-s[j]-c)^2 + 2*v*(s[i]-s[j]-c) + v^2

因为决策k是优于决策j的,所以f[k]<=f[j]

问了几个人都管不了(s[i]-s[k]-c)^2 QAQ,求大神指教QAQ

根据显然法可得,只需要证明 2*v*(s[i]-s[k]-c)<=2*v*(s[i]-s[j]-c),黄学长直接跳到这里技术分享

然后s[j]<=s[k]

然后求斜率优化

f[k]+(s[i]-s[k]-c)^2<=f[j]+(s[i]-s[j]-c)^2

展开略

(f[k]+(s[k]+c)^2-f[j]-(s[j]+c)^2)/(2*(s[k]-s[j]))<=f[i]

然后优化斜率

内个(s[i]-s[k]-c)^2怎么都想不明白,心好累qaq

代码:

技术分享
 1 #include<iostream> 2 #include<cstdio> 3 #include<algorithm> 4 #include<cstring> 5 #include<cmath> 6 using namespace std; 7 int read(){int z=0,mark=1;  char ch=getchar(); 8     while(ch<0||ch>9){if(ch==-)mark=-1;  ch=getchar();} 9     while(ch>=0&&ch<=9){z=(z<<3)+(z<<1)+ch-0;  ch=getchar();}10     return z*mark;11 }12 int n,m;13 int dui[51000],tou=0,wei=1;14 long long f[51000],s[51000];15 long long fang(long long x){  return x*x;}16 double get_ratio(int y,int x){  return ((f[x]-f[y]+fang(s[x]+m)-fang(s[y]+m))/(2.0*(s[x]-s[y])));}//斜率是右边-左边,所以这里参数先输入y,再输入x17 void dp(){18     dui[tou=1]=0;19     for(int i=1;i<=n;i++){20         while(wei<tou && get_ratio(dui[wei],dui[wei+1])<=s[i])  wei++;21         int temp=dui[wei];22         f[i]=f[temp]+fang(s[i]-s[temp]-m);23         while(wei<tou && get_ratio(dui[tou],i)<get_ratio(dui[tou-1],dui[tou]))  tou--;24         dui[++tou]=i;25     }26 }27 int main(){//freopen("ddd.in","r",stdin);28     cin>>n>>m;  m++;29     s[0]=0;30     for(int i=1;i<=n;i++)  s[i]=s[i-1]+read();31     for(int i=1;i<=n;i++)  s[i]+=i;32     dp();33     cout<<f[n]<<endl;34     return 0;35 }
View Code

 

【BZOJ1010】【HNOI2008】玩具装箱