题意:对序列任意分组:每一组对答案的贡献是 (len-1+sum[j]-sum[i]-L)^2 //L是题目给的常数
解:
1.列出简单的DP方程发现: i,j 变量可以分开,两个对答案的贡献是独立的
2.考虑斜率优化——>f[i]=f[j]+pf( i-(j+1)+s[i]-s[j]-L );
2*(s[i]+i-1-L)*(s[j]+j)+f[i] -pf(s[i]+i-1-L)==f[j]+pf(s[j]+j);
K x + b ==Y
3.DP()过程
(1)首先 用当前i的K去删掉队头元素
(2)直接转移
(3)维护下凸(以为求最小值)
#include<bits/stdc++.h>
#define mod 51061
#define en '\n'
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) (a>b? a:b)
#define ll long long
const ll maxn = 5e4+100;
const ll inf=0x3f3f3f3f;
ll mo;
using namespace std;
ll read() {
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9') {
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9') {
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
ll n,L;
ll c[maxn],s[maxn],q[maxn];
ll dp[maxn];
#define inl inline
#define pf(a) ((a)*(a))
double calk(ll x,ll y){
double Y=dp[y]-dp[x]+pf(s[y]+y)-pf(s[x]+x);
double X=s[y]-s[x]+y-x;
return Y/X;
}
signed main() {
#ifdef local
freopen("input2.txt","r",stdin);
#endif // local
n=read();
L=read();
for(ll i=1;i<=n;i++){
c[i]=read();
s[i]=s[i-1]+c[i];
}
ll l=1,r=1;
q[1]=0;
for(ll i=1;i<=n;i++){
while(l<r and calk(q[l],q[l+1])<=2*(s[i]+i-1-L) ){
l+=1;
}
dp[i]=(dp[q[l]]+ pf(i-(q[l]+1)+(s[i]-s[q[l]])-L) );
while(l<r and calk(q[r-1],i)<=calk(q[r-1],q[r]))r-=1;
q[++r]=i;
}
cout<<dp[n]<<en;
return 0;
}