发现长得好像什么石子合并之内的题目,然后探究探究,得出了一个结论:分割点相同,分割的顺序是没有关系的。
然后就想到了DP。设f[i][j]表示在第i次分割时,在j点分割。
转移引进一个x就可以了f[i][j]=max(f[x][j-1]+sum[x]*(sum[i]-sum[x])),打个前缀和,很显然。
复杂度 (O(n2k)) 。
发现DP的有一维其实是没有什么用的,可以打成滚动数组,然后就只剩下一个有用维度了,一般只用一维的DP都可以打斜率优化。
打完斜率优化得到个这个东西:
#include
#include
#include
#include
#include
#include
#define fo(i,a,b) for(i=a;i<=b;i++)
typedef long long ll;
using namespace std;
const int maxn=100007;
int i,j,k,t,n,m,x,v;
int g[maxn][207];
int d[maxn],l,r,ans[maxn];
ll a[maxn],sum[maxn],f[2][maxn];
ll mu(int x,int y,int i){
return f[i][x]-sum[x]*sum[x]-f[i][y]+sum[y]*sum[y];
}
ll zi(int x,int y){
return sum[y]-sum[x];
}
int main(){
freopen("sequence.in","r",stdin);
freopen("sequence.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)scanf("%lld",&a[i]),sum[i]+=sum[i-1]+a[i];
fo(j,1,m){
l=1,r=0,d[l]=0,v^=1;
fo(i,1,n){
while(l1],v^1)<=zi(d[l],d[l+1])*sum[i])l++;
f[v][i]=f[v^1][d[l]]+sum[d[l]]*(sum[i]-sum[d[l]]);
g[i][j]=d[l];
while(r>l&&mu(d[r-1],d[r],v^1)*zi(d[r],i)>=zi(d[r-1],d[r])*mu(d[r],i,v^1))r--;
d[++r]=i;
}
}
printf("%lld\n",f[v][n]);
j=0;
for(i=g[n][m];i;i=g[i][m-j]){
j++;ans[j]=i;
}
fo(i,1,m)printf("%d ",ans[i]);
}