首页 > 代码库 > bzoj1010: [HNOI2008]玩具装箱toy(斜率优化DP)
bzoj1010: [HNOI2008]玩具装箱toy(斜率优化DP)
codevs也有这题,伪·双倍经验233
首先朴素DP方程很容易看出:f[i]=min(f[j]+(i-j-1+sum[i]-sum[j]-L)^2);
于是设g[i]=i+sum[i]
g[j]=j+sum[j]
c=1+L
则f[i]=min(f[j]+(g[i]-g[j]-c)^2)
证明决策单调性,假设 j 比 k 优
f[j]+(g[i]-g[j]-c)^2<f[k]+(g[i]-g[k]-c)^2
证明f[j]+(g[x]-g[j]-c)^2<f[k]+(g[x]-g[k]-c)^2
f[j]+(g[i]+y-g[j]-c)^2<f[k]+(g[i]+y-g[k]-c)^2
f[j]+(g[i]-g[j]-c)^2-2*y*(g[i]-g[j]-c)<f[k]+(g[i]-g[k]-c)^2-2*y*(g[i]-g[k]-c)
g[j]>g[k]
所以当 j > k 时,j 比 k 优,则 j 一直比 k 优。
然后就可以斜率优化啦
f[j]+(g[i]-g[j]-c)^2<f[k]+(g[i]-g[k]-c)^2
f[j]-2*g[i]*(g[j]+c)+(g[j]+c)^2<f[k]-2*g[i]*(g[k]+c)+(g[k]+c)^2
(f[j]+(g[j]+c)^2-f[k]-(g[k]+c)^2)/(2*(g[k]-g[j]))<g[i]
所以斜率是递增的,维护个下凸包
#include<iostream> #include<cstring> #include<cstdlib> #include<cstdio> #define ll long long using namespace std; const int maxn=500010; int l,r; ll n,L,sum[maxn],g[maxn],q[maxn],f[maxn]; void read(ll &k) { int f=1;k=0;char c=getchar(); while(c<‘0‘||c>‘9‘)c==‘-‘&&(f=-1),c=getchar(); while(c<=‘9‘&&c>=‘0‘)k=k*10+c-‘0‘,c=getchar(); k*=f; } ll sqr(ll x){return x*x;} ll xl(int j,int k){return (f[j]+sqr(g[j]+1+L)-f[k]-sqr(g[k]+1+L))/(2*(g[j]-g[k]));} int main() { read(n);read(L); for(int i=1;i<=n;i++) read(sum[i]),sum[i]+=sum[i-1]; for(int i=1;i<=n;i++) { g[i]=i+sum[i]; while(l<r&&xl(q[l],q[l+1])<g[i])l++; f[i]=f[q[l]]+sqr(g[i]-g[q[l]]-1-L); while(l<r&&xl(q[r],q[r-1])>xl(i,q[r]))r--; q[++r]=i; } printf("%lld\n",f[n]); }
bzoj1010: [HNOI2008]玩具装箱toy(斜率优化DP)
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。