bzoj 1010 [HNOI2008]玩具装箱toy (斜率优化DP)

队列维护下凸包裸题

式子不太好推,但其实不用把式子全展开的.....

k单调递增,x单调递增,队列维护一下就行了

因为f[i]期望最小值,所以维护下凸包

好像记录一下凸包的坐标能减少常数

#include <cstdio>
#include <algorithm>
#include <cstring>
#define il inline
#define ll long long
#define N 51000
using namespace std;
int n,que[N];
ll L,f[N],c[N],s[N];
int gc()
{
    int rett=0,fh=1;char c=getchar();
    while(c<'0'||c>'9'){if(c=='-')fh=-1;c=getchar();}
    while(c>='0'&&c<='9'){rett=(rett<<3)+(rett<<1)+c-'0';c=getchar();}
    return rett*fh;
}
il ll yy(ll j){return f[j]+2ll*(s[j]+j)*(1ll+L)+(s[j]+j)*(s[j]+j)+(1ll+L)*(1ll+L);}
il ll xx(ll j){return s[j]+j;}
il ll kk(ll i){return 2ll*(s[i]+i);}

int main()
{
    n=gc(),L=gc();
    for(int i=1;i<=n;i++) c[i]=gc();
    for(int i=1;i<=n;i++) s[i]=s[i-1]+c[i];
    int hd=1,tl=1;
    for(ll i=1;i<=n;i++)
    {
        while(hd+1<=tl&&yy(que[hd])-kk(i)*xx(que[hd])>=yy(que[hd+1])-kk(i)*xx(que[hd+1]))
            hd++;
        f[i]=yy(que[hd])-kk(i)*xx(que[hd])+(s[i]+i)*(s[i]+i)-2ll*(s[i]+i)*(1ll+L);
        while(hd+1<=tl&&(yy(i)-yy(que[tl]))*(xx(que[tl])-xx(que[tl-1])) <= (yy(que[tl])-yy(que[tl-1]))*(xx(i)-xx(que[tl])))
            tl--;
        que[++tl]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}


猜你喜欢

转载自blog.csdn.net/guapisolo/article/details/82631997