玩具装箱
不难推出递推方程:dp[i]=min{dp[j]+(sum[i]+i−sum[j]−j−L−1)^2}
不妨设A=i+sum[i],B=j+sum[j]+1。则递推式可以转化为:dp[i]=min{dp[j]+(A-B+L)^2}
接下来的部分留给读者自行推倒(主要是我懒得写了QAQ)
看代码:
#include<bits/stdc++.h>
using namespace std;
#define int long long
const int maxn=100000;
int n,L,f[maxn],q[maxn];
int c[maxn],sum[maxn];
int a(int i){
return i+sum[i];
}
int b(int i){
return i+sum[i]+1;
}
int x(int i,int j){
return b(j)-b(i);
}
int y(int i,int j){
return f[j]+b(j)*b(j)-f[i]-b(i)*b(i);
}
signed main(){
cin>>n>>L;
for(int i=1;i<=n;i++){
scanf("%lld",&c[i]);
sum[i]=sum[i-1]+c[i];
}
memset(f,0x3f,sizeof(f));
int l=1,r=1;
q[l]=0;f[0]=0;
for(int i=1;i<=n;i++){
while(l<r&&y(q[l],q[l+1])<=x(q[l],q[l+1])*2*(a(i)-L))l++;
f[i]=f[q[l]]+(a(i)-b(q[l])-L)*(a(i)-b(q[l])-L);
while(l<r&&y(q[r-1],q[r])*x(q[r],i)>=x(q[r-1],q[r])*y(q[r],i))r--;
q[++r]=i;
}
cout<<f[n]<<endl;
return 0;
}