题意:(N(N<=50000))件玩具,每件玩具有一个长度(c_i),将玩具分成若干批,如果将第i件玩具到第j个玩具分作一批,那么该批的长度将为(x=j-i+sum_{k=i}^j c_k),每批的代价为((x-L)^2),(L)是一个给定的常数,求最小代价和.
分析:设(f[i])表示将前i件玩具分成若干批的最小代价,则(f[i]=f[j]+(i-(j+1)+sum[i]-sum[j]-L)^2)
假设(k<j)且j比k更优,即,
(f[j]+(i-j-1+sum[i]-sum[j]-L)^2<f[k]+(i-k-1+sum[i]-sum[k]-L)^2)
设(A[i]=i+sum[i]-L-1,g[i]=i+sum[i]),则有
设(f[j]+(A[i]-g[j])^2<f[k]+(A[i]-g[k])^2)
乱搞一下上式得到,
(frac{f[j]-g[j]^2-f[k]-g[k]^2}{g[j]-g[k]}<2A[i])
#include<bits/stdc++.h>
#define LL long long
using namespace std;
inline int read(){
int s=0,w=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){s=s*10+ch-'0';ch=getchar();}
return s*w;
}
const int N=50005;
int a[N],q[N];
LL sum[N],A[N],g[N],f[N];
int main(){
int n=read(),L=read();
for(int i=1;i<=n;i++){
a[i]=read();
sum[i]=sum[i-1]+a[i];
A[i]=i+sum[i]-L-1;
g[i]=i+sum[i];
}
int l=1,r=1;q[1]=0;
memset(f,0x3f,sizeof(f));f[0]=0;
for(int i=1;i<=n;i++){
while(l<r&&(f[q[l+1]]-f[q[l]]+g[q[l+1]]*g[q[l+1]]-g[q[l]]*g[q[l]])<=(2*A[i]*(g[q[l+1]]-g[q[l]])))l++;
f[i]=f[q[l]]+(A[i]-g[q[l]])*(A[i]-g[q[l]]);
while(l<r&&(f[q[r]]-f[q[r-1]]+g[q[r]]*g[q[r]]-g[q[r-1]]*g[q[r-1]])*(g[i]-g[q[r]])>=(f[i]-f[q[r]]+g[i]*g[i]-g[q[r]]*g[q[r]])*(g[q[r]]-g[q[r-1]]))r--;
q[++r]=i;
}
printf("%lld
",f[n]);
return 0;
}