首页 写随笔

cdcq(本博客废弃!现用博客:https://www.cnblogs.com/cdcq/)

本博客废弃!现用博客:https://www.cnblogs.com/cdcq/

导航

【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,再输入x
17 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

 

posted on 2016-09-29 17:51  cdcq_old  阅读(296)  评论(0编辑  收藏  举报