[HNOI2008]玩具装箱TOY

传送门


由题意可得:

\(dp[i]=min\{dp[j]+(i-j-1+sum[i]-sum[j]-L)^2\}\)

\(令x[i]=sum[i]+i,P=L+1,则\):

\(dp[i]=min\{dp[j]+(x[i]-x[j]-P)^2\}\)

如果有从a转移比从b转移优,则有:

\(dp[a]+(x[i]-x[a]-P)^2<dp[b]+(x[i]-x[b]-P)^2\)

即:

\[{dp[a]-dp[b]+x[a]^2-x[b]^2\over x[b]-x[a]}>2*(P-x[i]) \]

到此步已经可以写出基于斜率优化的代码(其实按上式代码实现更易)

#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read()
{
	int x=0,f=1;char ch=getchar();
	while (ch<'0'||ch>'9') ch=='-'&&(f=-1),ch=getchar();
	while (ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();
	return x*f;
}
const int N=50010;
int que[N];
ll dp[N],su[N];
int n,m,l=0,r=0;
ll sqr(ll x){return x*x;}
double get(int x,int y){return 1.0*(dp[y]-dp[x]+sqr(su[y])-sqr(su[x]))/(su[x]-su[y]);}
int main()
{
	n=read(),m=read()+1;
	for (int i=1;i<=n;++i)
		su[i]=su[i-1]+read();
	for (int i=1;i<=n;++i)
	{
	    su[i]+=i;
		double k=2ll*(m-su[i]);
		while (l<r&&get(que[l],que[l+1])>k) ++l;
		dp[i]=dp[que[l]]+sqr(su[i]-su[que[l]]-m);
		while (l<r&&get(que[r],i)>get(que[r-1],que[r])) --r;
		que[++r]=i;
	}
	printf("%lld",dp[n]);
	return 0;
}

\(y[i]=dp[i]+x[i]^2,k[i]=2*(P-x[i])\),上式可化为:

\[y[a]-k[i]*x[a]<y[b]-k[i]*x[b] \]

$$(形如y-kx),即为真·斜率优化$$

posted @ 2018-08-21 23:43  蒟蒻czx  阅读(71)  评论(0)    收藏  举报