[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]
\]

浙公网安备 33010602011771号