BZOJ1010 [HNOI2008]玩具装箱toy(斜率优化dp)

【题解】


设 f[i]表示将第1~i个物品装箱后,费用的最小值,答案为f[n]

   s[i]=c[1]+c[2]+……+c[i]
则:f[0]=0
f[i]=min{ f[j]+(s[i]-s[j]+i-j-1-L)^2 } ( i>0 , 0<=j<i )
================================================================================
考虑斜率优化:
对于任意i>1,若j不比k差( 0<=j,k<i , j!=k )
则:f[j]+(s[i]-s[j]+i-j-1-L)^2 <= f[k]+(s[i]-s[k]+i-k-1-L)^2                    设 x[i]=s[i]+i,如此,与j,k有关的变量各少一个,且j,k形式对应 
=>      f[j]+(x[i]-x[j]-L-1)^2 <= f[k]+(x[i]-x[k]-L-1)^2                        设 mi=x[i]-L-1,如此,与j,k无关的量仅剩一个 
=>            f[j]+(mi-x[j])^2 <= f[k]+(mi-x[k])^2
=>       f[j]+x[j]^2-2*mi*x[j] <= f[k]+x[k]^2-2*mi*x[k]
=>     f[j]+x[j]^2-f[k]-x[k]^2 <= 2*mi*(x[j]-x[k])                              设 y[i]=f[i]+x[i]^2
=>                   y[j]-y[k] <= 2*mi*(x[j]-x[k])
∵ x单调递增,设 K[j,k]=(y[j]-y[k])/(x[j]-x[k]) 即斜率 

得到结论:若k<j,K[j,k]<=2*mi (斜率小,后优)
          若j<k,K[j,k]>2*mi  (斜率大,前优)
================================================================================
构造下凸函数:
若 j<k<l,且j-k-l连线上凸(即K[j,k]>K[k,l])
则有:若 K[j,k]>2*m*i,则j比k优 
      若 K[j,k]<=2*m*i,则K[k,l]<K[j,k]<=2*m*i,l比k优 
即 上凸、不凸时k对i永远不会最优,可删去k
∴ j-k-l下凸 

将符合此条件的j,k,l,……依次加入队列,j,k为前两项 
若 对于一个i,有K[j,k]<=2*mi (k比j优)
∵ m单调递增 
∴ 对于t>i,必有 K[j,k]<=2*mt (k总比j优)
此时可删去队首j
================================================================================

注意边界:j>=0 -> 0要先纳入队列 


【代码】

#include<stdio.h>
#include<stdlib.h>
typedef long long LL;
LL f[50005]={0},s[50005]={0},x[50005]={0},y[50005]={0};
int q[50005]={0};
double K(int i,int j)//其实会有浮点误差,改成long long乘法比较好 
{
	return (double)(y[i]-y[j])/(double)(x[i]-x[j]);
}
int main()
{
	LL L,m;
	int n,i,head=0,tail=0;
	scanf("%d%lld",&n,&L);
	for(i=1;i<=n;i++)
	{
		scanf("%lld",&s[i]);
		s[i]+=s[i-1];
	}
	for(i=1;i<=n;i++)//0已加入 
	{
		x[i]=s[i]+i;
		m=x[i]-L-1;
		while(head<tail&&K(q[head],q[head+1])<=(double)2*m) head++;//删去不是最优的队首元素 
		f[i]=f[q[head]]+(m-x[q[head]])*(m-x[q[head]]);//此时队首元素即为最优值,用它更新i
		y[i]=f[i]+x[i]*x[i];
		while(tail>head&&K(q[tail-1],q[tail])>=K(q[tail],i)) tail--;//维护下凸壳 
		q[++tail]=i;//将i入队 
	}
	printf("%lld",f[n]);
	return 0;
}


你可能感兴趣的:(斜率优化)