BZOJ1010: [HNOI2008]玩具装箱toy


BZOJ1010: [HNOI2008]玩具装箱toy##

  Time Limit: 1 Sec
  Memory Limit: 162 MB

Description###

  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。但他希望费用最小.
 

Input###

   第一行输入两个整数N,L.接下来N行输入Ci.1<=N<=50000,1<=L,Ci<=10^7
 

Output###

   输出最小费用
 

Sample Input###

  5 4
  3
  4
  2
  1
  4
 

Sample Output###

  1
    

HINT

题目地址:BZOJ1010: [HNOI2008]玩具装箱toy

题目大意: 做的心烦意乱,不写了

题解:

  by hzw
  $$dp[i]=min(dp[j]+(sum[i]-sum[j]+i-j-1-L)^2) (j<i)$$
   (f[i]=sum[i]+i,c=1+l)
   (dp[i]=min(dp[j]+(f[i]-f[j]-c)^2))
  1.证明决策单调性
  假设在状态 (i) 处的 (k) 决策优与 (j) 决策,即
  $$dp[k]+(f[i]-f[k]-c)2<=dp[j]+(f[i]-f[j]-c)2$$
  则对于 (i) 后的所有状态 (t),要证明决策单调性
   (dp[k]+(f[t]-f[k]-c)^2<=dp[j]+(f[t]-f[j]-c)^2)
  只要证
  $$dp[k]+(f[i]+v-f[k]-c)2<=dp[j]+(f[i]+v-f[j]-c)2$$
  只要证
  $$dp[k]+(f[i]-f[k]-c)2+2*v*(f[i]-f[k]-c)+v2<=dp[j]+(f[i]-f[j]-c)2+2*v*(f[i]-f[j]-c)+v2$$
  只要证
  $$2v(f[i]-f[k]-c)<=2v(f[i]-f[j]-c)$$
   (f[k]>=f[j])(显然)
  证明完毕
  2.求斜率方程
  因为 (dp[k]+(f[i]-f[k]-c)^2<=dp[j]+(f[i]-f[j]-c)^2)
  展开
  $$dp[k]+f[i]2-2*f[i]*(f[k]+c)+(f[k]+c)2<=dp[j]+f[i]2-2*f[i]*(f[j]+c)+(f[j]+c)2$$
  
  $$dp[k]-2f[i](f[k]+c)+(f[k]+c)2<=dp[j]-2*f[i]*(f[j]+c)+(f[j]+c)2$$
   ((dp[k]+(f[k]+c)^2-dp[j]-(f[j]+c)^2)/2*(f[k]-f[j])<=f[i])
  (f[i]) 是单调递增的,我们使用队列维护一个下凸壳,每次取出队头作为决策
  加入决策 (i) 时,令队尾为 (q[r])前一个为 (q[r-1])
  满足 (斜率 (q[r],i) < 斜率(q[r-1],q[r])) 时,显然队尾是无效的,将其弹出
  具体看代码
  还有一位dalao写得超级好懂
  大米饼


AC代码

#include <stdio.h>
#define ll long long
using namespace std;
const int N=5e4+5;
int n,L;
int q[N];
ll s[N],dp[N];
inline double X(int i){
	return s[i];
}
inline double Y(int i){
	return dp[i]+(s[i]+L)*(s[i]+L); 
}
inline double rate(int i,int k){
	return (Y(k)-Y(i))/(X(k)-X(i));
}
int main(){
	scanf("%d%d",&n,&L);L++;
	for(int i=1;i<=n;i++){
		scanf("%lld",&s[i]);
		s[i]+=s[i-1];
	}
	for(int i=1;i<=n;i++)
		s[i]+=i;
	int l=1,r=1;q[1]=0;
	for(int i=1;i<=n;i++){
		while(l<r && rate(q[l],q[l+1])<2*s[i])l++;
		int t=q[l];
		dp[i]=dp[t]+(s[i]-s[t]-L)*(s[i]-s[t]-L);
		while(l<r && rate(q[r-1],q[r])>rate(q[r],i))r--;
		q[++r]=i;
	}
	printf("%lld
",dp[n]);
	return 0;
}


  作者:skl_win
  出处:https://www.cnblogs.com/shaokele/
  本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

原文地址:https://www.cnblogs.com/shaokele/p/9594552.html