版权声明:随意转载哦......但还是请注明出处吧: https://blog.csdn.net/dreaming__ldx/article/details/82531382
传送门
把式子展开后发现就是要求:
的最小值。
于是只需要求:
的最小值。
于是设
表示前i个分了j组的最小值。
显然有:
<=>
对于两个决策
且k2比k1更优,有:
>
令
=>
果断斜率优化。
代码:
#include<bits/stdc++.h>
#define ll long long
#define N 3005
using namespace std;
inline ll read(){
ll ans=0;
char ch=getchar();
while(!isdigit(ch))ch=getchar();
while(isdigit(ch))ans=(ans<<3)+(ans<<1)+(ch^48),ch=getchar();
return ans;
}
int n,m,hd,tl,q[N];
ll sum[N],f[N][N];
inline double slope(int k,int i,int j){return 1.0*(f[i][k]+sum[i]*sum[i]-f[j][k]-sum[j]*sum[j])/(sum[i]-sum[j]);}
int main(){
n=read(),m=read();
for(int i=1;i<=n;++i)sum[i]=sum[i-1]+read(),f[i][0]=1e18;
for(int j=1;j<=m;++j){
hd=tl=1,q[1]=0;
for(int i=1;i<=n;++i){
while(hd<tl&&slope(j-1,q[hd+1],q[hd])<2.0*sum[i])++hd;
int k=q[hd];
f[i][j]=f[k][j-1]+(sum[i]-sum[k])*(sum[i]-sum[k]);
while(hd<tl&&slope(j-1,q[tl],q[tl-1])>slope(j-1,i,q[tl]))--tl;
q[++tl]=i;
}
}
cout<<(m*f[n][m]-sum[n]*sum[n]);
return 0;
}