1010: [HNOI2008]玩具装箱toy DP+斜率优化+决策单调性

来源:互联网 发布:淘宝定制t恤好的店铺 编辑:程序博客网 时间:2024/04/28 11:03

好久没做斜率优化辣,突然发现Page1上有一道斜率优化的裸题,借此来回顾一下。


首先我们可以DP,令fi表示前i个玩具装箱花费的最小费用。
O(n2)的DP显然:

fi=min{fj+(ij1+k=j+1ickL)2}

我们维护ci的前缀和sumi,上式转化为
fi=min{fj+(sumiL+i1+sumjj)2}

然后为表述方便,我们令gi=sumi+iL1,令xi=sumi+i
所以上式转化为
fi=min{fj+(gixj)2}=min{fj+g2i+x2j2gixj}

考虑这个方程有没有单调性:
0<=k<j<i,且取j更优,即:
fk+x2k2gixk>fj+x2j2gixj

移项:
(fk+x2k)(fj+x2j)>2hi(xkxj)

我们令yi=fi+x2i,容易发现xi,yi均单调,所以继续移项我们有:
ykyjxkxj<2gi

这是一个看起来类似斜率的式子。
由于xi,yi,gi均单调,所以如果某一个点不如它之后的点,这个点以后再也不会被用到,所以我们可以用单调队列来维护一个下凸壳,取得最优决策的点一定在凸壳上。
然后就好啦~这是最裸的斜率优化+决策单调性辣。

#include<iostream>#include<cstdio>#define ll long long #define N 50005using namespace std;int n,L;int q[N];ll c[N],sum[N],X[N],Y[N],f[N],g[N];inline ll read(){    ll a=0,f=1; char c=getchar();    while (c<'0'||c>'9') {if (c=='-') f=-1; c=getchar();}    while (c>='0'&&c<='9') {a=a*10+c-'0'; c=getchar();}    return a*f;}int main(){    n=read(); L=read();    for (int i=1;i<=n;i++) c[i]=read(),sum[i]=sum[i-1]+c[i];    int l=0,r=0;    for (int i=1;i<=n;i++)    {        g[i]=sum[i]+i-L-1;        while (l<r&&Y[q[l+1]]-Y[q[l]]<=2*(X[q[l+1]]-X[q[l]])*g[i]) l++;        f[i]=Y[q[l]]+g[i]*g[i]-2*g[i]*X[q[l]];        X[i]=sum[i]+i;        Y[i]=f[i]+X[i]*X[i];        while (l<r&&(Y[i]-Y[q[r]])*(X[q[r]]-X[q[r-1]])<=(Y[q[r]]-Y[q[r-1]])*(X[i]-X[q[r]])) r--;        q[++r]=i;    }    cout << f[n] << endl;    return 0;}
1 0
原创粉丝点击