P3195 [HNOI2008]玩具装箱

(f_i) 表示前 (i) 个玩具都已经放入容器的最小费用。对 (C) 做一遍前缀和。

转移直接枚举上一次分段:

[f_i=min{f_j+(i-j-1+C_i-C_j-L)^2|j<i} ]

考虑两个决策 (j,k(j<k)),若 (j)(k) 优:

[f_j+(i-j+C_i-C_j-L-1)^2<f_k+(i-k+C_i-C_k-L-1)^2 ]

[f_j-f_k<(C_i+i-L-1-C_k-k)^2-(C_i+i-L-1-C_j-j)^2 ]

(t=C_i+i-L-1)

[f_j-f_k<(t-C_k-k)^2-(t-C_j-j)^2 ]

[f_j-f_k<t^2-2 imes t imes(C_k+k)+(C_k+k)^2-t^2+2 imes t imes(C_j+j)-(C_j+j)^2 ]

[f_j+(C_j+j)^2-f_k-(C_k+k)^2<2 imes t imes(C_j+j-C_k-k) ]

[dfrac{f_j+(j+C_j)^2-f_k-(k+C_k)^2}{C_j+j-C_k-k}>2 imes t ]

因为 (t) 随着 (i) 的增大单调不减,所以对 ((C_i+i,f_i+(i+C_i)^2)) 维护一个上凸包。

时间复杂度 (Oleft(n ight))

code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define N 50005
#define Db double
#define For(i,x,y)for(i=x;i<=(y);i++)
int que[N];
ll f[N],c[N];
inline ll sqr(ll x)
{
	return x*x;
}
inline Db slope(int j,int k)
{
	return Db(f[j]+sqr(j+c[j])-f[k]-sqr(k+c[k]))/Db(c[j]+j-c[k]-k);
}
int main()
{
	int n,l,i,head,tail;
	head=tail=1;
	scanf("%d%d",&n,&l);
	For(i,1,n)scanf("%d",&c[i]),c[i]+=c[i-1];
	For(i,1,n)
	{
		while(head<tail&&slope(que[head],que[head+1])<=(c[i]+i-l-1)<<1)head++;
		/*printf("%d
",que[head]);*/
		f[i]=f[que[head]]+sqr(i-que[head]-1+c[i]-c[que[head]]-l);
		while(head<tail&&slope(que[tail-1],que[tail])>=slope(que[tail-1],i))tail--;
		que[++tail]=i;
	}
	printf("%lld",f[n]);
	return 0;
}
原文地址:https://www.cnblogs.com/May-2nd/p/14247651.html