点击这里查看原题
因为切割的位置相同时,顺序对结果没有影响,所以可以得到DP方程:f[i][j]=max{f[i-1][k]+(sum[n]-sum[j])*(sum[j]-sum[k])}
可以使用斜率优化,复杂度O(nk),外侧循环切割次数,内层循环切割位置。不过注意,因为空间只有128mb,因此要使用滚动数组。(如果在BZOJ上交出现了0ms的TLE,一定是因为MLE了)
/*
User:Small
Language:C++
Problem No.:3675
*/
#include<bits/stdc++.h>
#define ll long long
#define inf 999999999
using namespace std;
const int M=1e5+5;
int n,k,head,tail,que[M],p,q,cnt;
ll f[2][M],a[M],sum[M],ans;
double slop(int j,int k,int t){
return (f[t][j]-f[t][k]+(sum[k]-sum[j])*sum[n])/(double)(sum[k]-sum[j]);
}
ll cal(int i,int j,int t){
return f[t][j]+(sum[n]-sum[i])*(sum[i]-sum[j]);
}
int main(){
freopen("data.in","r",stdin);//
scanf("%d%d",&n,&k);
for(int i=1;i<=n;i++){
scanf("%lld",&a[i]);
if(a[i]!=0){
a[++cnt]=a[i];
sum[cnt]=sum[cnt-1]+a[i];
}
}
n=cnt;
p=0,q=1;
for(int t=1;t<=k;t++){
head=tail=0;
for(int i=1;i<=n;i++){
while(head<tail&&slop(que[head],que[head+1],p)<sum[i]) head++;
f[q][i]=cal(i,que[head],p);
while(head<tail&&slop(que[tail-1],que[tail],p)>slop(que[tail],i,p)) tail--;
que[++tail]=i;
if(t==k) ans=max(ans,f[q][i]);
}
swap(p,q);
}
printf("%lld\n",ans);
return 0;
}