题目链接:
首先很容易地我们可以得到一个(O(n^2))的算法:
设(f_{[i]})表示前(i)个玩具的最小费用,(Sum_{[i]})表示前(i)个玩具的长度和,则有转移方程:
[f_{[i]}=min_{0le 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_{0le 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
",f[n]);
return 0;
}