8
27
2015
0

1010: [HNOI2008]玩具装箱toy

1010: [HNOI2008]玩具装箱toy

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
 

 

法1:O(n logn)    栈优化走起!

#include<cstdio>
#define MaxN 50010
typedef long long LL;
int N,L;
LL A[MaxN],f[MaxN];
int st[MaxN],w,t,b[MaxN],e[MaxN];
LL pow(LL x){
	return x*x;
}
LL calc(int x,int y){
	return f[x]+pow(A[y]-A[x]-1-L);
}
int main(){
	scanf("%d%d",&N,&L);
	for (int i=1;i<=N;++i)
	    scanf("%lld",&A[i]);
	for (int i=1;i<=N;++i)
		A[i]+=A[i-1]+1;
    b[0]=0;
	e[ st[ w=t=0 ]=0 ]=N;
    for (int i=1;i<=N;++i){
		while ( e[ st[w] ]<i ) ++w;
		b[ st[w] ]=i;
		f[i]=calc(st[w],i);
		if ( calc(st[t],N) < calc(i,N) ) continue;
		while ( w<=t && calc(st[t],b[st[t]]) >= calc(i,b[st[t]]) ) --t;
		int be=e[ st[t] ]+1,l=b[ st[t] ],r=e[ st[t] ];
		while (l<=r){
			int mid=(l+r)/2;
			if ( calc(st[t],mid) >= calc(i,mid) ){
				be=mid; r=mid-1;
			}
			else l=mid+1;
		}
		e[ st[t] ]=be-1; st[++t]=i; b[i]=be; e[i]=N; 
    }
    printf("%lld\n",f[N]);
}

 

法2:O(n)    美妙的斜率优化。。。

      蒟蒻wy表示写完整个人都斜率优化了。。。

#include<cstdio>
#define MaxN 50010
typedef long long LL;
int N,L,Q[MaxN],ql,qr;
LL sum[MaxN],a[MaxN],b[MaxN],X[MaxN],Y[MaxN],f[MaxN];
LL calc(int x,int y){
    return f[x]+b[x]*b[x]-2*a[y]*b[x];
}
bool check(int p,int q,int o){
	return (X[p]-X[o])*(Y[q]-Y[o])-(X[q]-X[o])*(Y[p]-Y[o])<=0;
}
int main(){
	scanf("%d%d",&N,&L);
	for (int i=1;i<=N;++i)
	    scanf("%lld",&sum[i]);
    for (int i=1;i<=N;++i){
		sum[i]+=sum[i-1];
		a[i]=sum[i]+i-L-1;
		b[i]=sum[i]+i;
    }
    for (int i=1;i<=N;++i){
		while ( ql<qr && calc(Q[ql],i)>=calc(Q[ql+1],i) ) ++ql;
		f[i]=calc(Q[ql],i)+a[i]*a[i];
		X[i]=b[i]; Y[i]=f[i]+b[i]*b[i];
		while ( ql<qr && check(Q[qr-1],Q[qr],i) ) --qr;
		Q[++qr]=i;
    }
    printf("%lld\n",f[N]);
}

 

Ps:以上两种解法详见 1D/1D动态规划优化初步

Category: BZOJ | Tags: DP bzoj 斜率优化 决策单调性 | Read Count: 331

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter

Host by is-Programmer.com | Power by Chito 1.3.3 beta | Theme: Aeros 2.0 by TheBuckmaker.com