[BZOJ1010/Luogu3195][HNOI2008]玩具装箱TOY

题目链接:

BZOJ1010

Luogu3195

首先很容易地我们可以得到一个\(O(n^2)\)的算法:

\(f_{[i]}\)表示前\(i\)个玩具的最小费用,\(Sum_{[i]}\)表示前\(i\)个玩具的长度和,则有转移方程:

\[f_{[i]}=\min_{0\le j<i}\{f_{[j]}+(Sum_{[i]}-Sum_{[j]}+i-j-1-L)^2\} \]

\(A_{[x]}=Sum_{[x]}+x\)\(B_{[x]}=Sum_{[x]}+x+1+L\),则:

\[f_{[i]}=\min_{0\le j<i}\{f_{[j]}+(A_{[i]}-B_{[j]})^2\} \]

\[f_{[i]}=f_{[j]}+A_{[i]}^2-2A_{[i]}B_{[j]}+B_{[j]}^2 \]

\[2A_{[i]}B_{[j]}+f_{[i]}-A_{[i]}^2=f_{[j]}+B_{[j]}^2 \]

\(X_{[x]}=B_{[x]}\)\(Y_{[x]}=f_{[j]}+B_{[j]}^2\),则:

\[2A_{[i]}X_{[j]}+f_{[i]}-A_{[i]}^2=Y_{[j]} \]

若使\(f_{[i]}\)最小,那么将上式看做一条斜率为\(2A_{[i]}\)的直线,使\(f_{[i]}-A_{[i]}^2\)最小,则有一点\((X_{[j]},Y_{[j]})\)到直线距离最短。

显然,此点一定在所有决策点组成的下凸包上。

那么套斜率优化维护下凸包就好了。

时间复杂度 \(O(n)\)(均摊)

#pragma GCC optimize(3)
#include <cstdio>
#include <cctype>
char File[300005],*p1=File,*p2=File;
 
inline char Getchar()
{
    return p1==p2&&(p2=(p1=File)+fread(File,1,300000,stdin),p1==p2)?EOF:*p1++;
}
 
inline int Getint()
{
    register int x=0;
    register char c;
    while(!isdigit(c=Getchar()));
    for(;isdigit(c);c=Getchar())x=x*10+c-48;
    return x;
}
 
int n,l,q[50005],qh,qt;
long long c[50005],f[50005];
 
inline long long A(int x){return c[x]+x;}
inline long long B(int x){return c[x]+x+l+1;}
inline long long X(int x){return B(x);}
inline long long Y(int x){return f[x]+B(x)*B(x);}
 
int main()
{
    n=Getint(),l=Getint();
    for(register int i=1;i<=n;++i)c[i]=Getint()+c[i-1];
    for(register int i=1;i<=n;++i)
    {
        while(qh<qt&&Y(q[qh+1])-Y(q[qh])<=2*A(i)*(X(q[qh+1])-X(q[qh])))++qh;
        f[i]=f[q[qh]]+(A(i)-B(q[qh]))*(A(i)-B(q[qh]));
        while(qh<qt&&(Y(q[qt])-Y(q[qt-1]))*(X(i)-X(q[qt]))>=(Y(i)-Y(q[qt]))*(X(q[qt])-X(q[qt-1])))--qt;
        q[++qt]=i;
    }
    printf("%lld\n",f[n]);
    return 0;
}
posted @ 2019-01-01 15:33  LanrTabe  阅读(134)  评论(0编辑  收藏  举报