【JZOJ1116】【BZOJ1010】玩具装箱TOY

description

8月P教授要去看奥运,但是他割舍不下自己的一大堆智力玩具。于是,他决定把所有玩具都运到北京去。P教授使用自己的物体维数压缩器ODZ(Object Dimension Zipper)来给玩具装箱。ODZ 可以将任意物品变成一维,再装到一种特殊的一维容器中。P教授有编号为1…N的N件玩具,第i件玩具经过ODZ处理后一维长度是Ci。为了方便整理,P教授要求在一个一维容器中的玩具编号是连续的。同时,如果一个一维容器中有多个玩具,那么相信两件玩具之间要加入1个单位长度的填充物。

形式地说,如果将第i到第j件玩具放在一个容器中,那容器的长度将为:

x=j-i+sigma(Ck) //i<=k<=j

制作容器的费用与容器长度有关。根据P教授的研究,如果容器长度为x,其制作费用为(x-L)^2,其中L是一个常量。P教授不关心容器的数目,他可以制造出任意长度的容器(甚至超过L),但他希望费用最小。


analysis

  • 一年多没打斜率优化忘光了……复习一下

  • f [ i ] f[i] f[i]表示到第 i i i位的最小值,那么 O ( n 2 ) O(n^2) O(n2) D P DP DP方程很好写

f [ i ] = m i n ( f [ j ] + ( p r e [ i ] − p r e [ j ] + i − j − l − 1 ) 2 ) f[i]=min(f[j]+(pre[i]-pre[j]+i-j-l-1)^2) f[i]=min(f[j]+(pre[i]pre[j]+ijl1)2)

  • g [ i ] = p r e [ i ] + i , m = l + 1 g[i]=pre[i]+i,m=l+1 g[i]=pre[i]+i,m=l+1,那么对于 k > j k>j k>j k k k j j j优则有

f [ k ] + ( g [ i ] − g [ k ] − c ) 2 ≤ f [ j ] + ( g [ i ] − g [ j ] − c ) 2 f[k]+(g[i]-g[k]-c)^2≤f[j]+(g[i]-g[j]-c)^2 f[k]+(g[i]g[k]c)2f[j]+(g[i]g[j]c)2

  • 拆项移项得

f [ k ] − 2 g [ i ] ( g [ k ] + c ) + ( g [ k ] + c ) 2 ≤ f [ j ] − 2 g [ i ] ( g [ j ] + c ) + ( g [ j ] + c ) 2 f[k]-2g[i](g[k]+c)+(g[k]+c)^2≤f[j]-2g[i](g[j]+c)+(g[j]+c)^2 f[k]2g[i](g[k]+c)+(g[k]+c)2f[j]2g[i](g[j]+c)+(g[j]+c)2

  • 再移

f [ k ] − f [ j ] ≤ 2 g [ i ] ( g [ k ] + c ) − ( g [ k ] + c ) 2 − 2 g [ i ] ( g [ j ] + c ) + ( g [ j ] + c ) 2 f[k]-f[j]≤2g[i](g[k]+c)-(g[k]+c)^2-2g[i](g[j]+c)+(g[j]+c)^2 f[k]f[j]2g[i](g[k]+c)(g[k]+c)22g[i](g[j]+c)+(g[j]+c)2

f [ k ] − f [ j ] + ( g [ k ] + c ) 2 − ( g [ j ] + c ) 2 ≤ 2 g [ i ] ( g [ k ] − g [ j ] ) f[k]-f[j]+(g[k]+c)^2-(g[j]+c)^2≤2g[i](g[k]-g[j]) f[k]f[j]+(g[k]+c)2(g[j]+c)22g[i](g[k]g[j])

  • 最后

f [ k ] − f [ j ] + ( g [ k ] + c ) 2 − ( g [ j ] + c ) 2 2 ( g [ k ] − g [ j ] ) ≤ g [ i ] { {f[k]-f[j]+(g[k]+c)^2-(g[j]+c)^2}\over{2(g[k]-g[j])}}≤g[i] 2(g[k]g[j])f[k]f[j]+(g[k]+c)2(g[j]+c)2g[i]

  • 然后按套路上单调队列斜率优化维护下凸壳就可以了

  • 注意先删去较劣的队头后删去较劣的队尾


code

#pragma GCC optimize("O3")
#pragma G++ optimize("O3")
#include
#include
#include
#define MAXN 50005
#define mod 1000000007
#define ll long long
#define reg register ll
#define fo(i,a,b) for (reg i=a;i<=b;++i)
#define fd(i,a,b) for (reg i=a;i>=b;--i)
#define O3 __attribute__((optimize("-O3")))

using namespace std;

ll a[MAXN],f[MAXN],g[MAXN],pre[MAXN],que[MAXN];
ll n,m;

O3 inline ll read()
{
     
	ll x=0,f=1;char ch=getchar();
	while (ch<'0' || '9'<ch){
     if (ch=='-')f=-1;ch=getchar();}
	while ('0'<=ch && ch<='9')x=x*10+ch-'0',ch=getchar();
	return x*f;
}
O3 inline ll sqr(ll x)
{
     
	return x*x;
}
O3 inline double slope(ll x,ll y)
{
     
	return 1.0*(f[x]+sqr(g[x]+m)-f[y]-sqr(g[y]+m))/(2.0*(g[x]-g[y]));
}
O3 int main()
{
     
	//freopen("T1.in","r",stdin);
	n=read(),m=read()+1;
	fo(i,1,n)pre[i]=pre[i-1]+(a[i]=read()),g[i]=pre[i]+i;
	ll head=1,tail=1;f[0]=que[1]=0;
	fo(i,1,n)
	{
     
		while (head<tail && slope(que[head+1],que[head])<=g[i])++head;
		f[i]=f[que[head]]+sqr(g[i]-g[que[head]]-m);
		while (head<tail && slope(que[tail],que[tail-1])>=slope(i,que[tail]))--tail;
		que[++tail]=i;
	}
	printf("%lld\n",f[n]);
	return 0;
}

你可能感兴趣的:(DP,模拟赛,单调队列,斜率优化)