\(F[i]=\min\{ F[j]+(lis[i]-lis[j]+i-j-1-L)^2 \}\)
\(f(i)=lis[i]+i,g(i)=f(i)+L+1\)
\(F[i]=F[j]+(f(i)-g(j))^2\)
\(F[i]=F[j]+f(i)^2-2f(i)g(j)+g(j)^2\)
\(F[j]=2f(i)g(j)+(F[i]-f(i)^2-g(j)^2)\)
以\(g(j)\)为横坐标,则直线斜率为\(2f(i)\)
单调队列维护下凸壳即可
#include"cstdio"
#include"cstring"
#include"iostream"
#include"algorithm"
using namespace std;
const int MAXN=5e4+5;
int n,L;
int q[MAXN];
long long lis[MAXN],F[MAXN];
long long get(int x){return lis[x]+L+x+1;}
long long got(int x){return F[x]+get(x)*get(x);}
bool cqr(int x1,int x2,int x3)
{
long long y3=lis[x3]+x3<<1ll;
return (got(x2)-got(x1))<=y3*(get(x2)-get(x1));
}
bool cqt(int x1,int x2,int x3)
{
return (got(x2)-got(x1))/(get(x2)-get(x1))*(get(x3)-get(x1))>=(got(x3)-got(x1));
}
int main()
{
scanf("%d%d",&n,&L);
for(int i=1;i<=n;++i) scanf("%lld",&lis[i]),lis[i]+=lis[i-1];
int hd=1,tl=1;
for(int i=1;i<=n;++i){
while(hd<tl&&cqr(q[hd],q[hd+1],i)) ++hd;
long long tmp=lis[i]-lis[q[hd]]+i-q[hd]-1-L;
F[i]=F[q[hd]]+tmp*tmp;
while(hd<tl&&cqt(q[tl-1],q[tl],i)) --tl;
q[++tl]=i;
}printf("%lld\n",F[n]);
return 0;
}