將一個序列切割\(k\)次,每次切割的收益是兩邊和的乘積,求最大收益.\(n\leqslant 1\times 10^5,k\leqslant 200\)c++
斜率優化DP..優化
由於什麼\((a+b)c+ab=a(b+c)+bc\)..spa
因此他是隻與結果有關的,跟切割方法無關,隨便切就行...blog
\(f[i][j]=max\{f[k][j-1]+s[k](s[i]-s[k])\}\)ip
斜率正好是前綴和,而且單調不降..get
因此直接斜率優化那一套就好了...it
/************************************************************** Problem: 3675 User: BeiYu Language: C++ Result: Accepted Time:14596 ms Memory:84112 kb ****************************************************************/ #include <bits/stdc++.h> using namespace std; typedef long long LL; const int N = 100005; const int M = 205; inline int in(int x=0,char ch=getchar()) { while(ch>'9'||ch<'0') ch=getchar(); while(ch>='0'&&ch<='9') x=x*10+ch-'0',ch=getchar();return x; } int n,k; int a[N],q[M][N],h[M],t[M]; LL s[N],f[N][2]; //#define B(i,j) (f[i][(j)&1]-s[i]*s[i]) //#define F(k,i,j) (B(k,((j)^1))+s[k]*s[i]) inline LL B(int i,int j) { return f[i][j&1]-s[i]*s[i]; } inline LL F(int k,int i,int j) { return B(k,j^1)+s[k]*s[i]; } int main() { // cout<<(sizeof(f)+sizeof(q)+sizeof(s)+sizeof(a))/1024.0/1024.0<<endl; n=in(),k=in();k++; for(int i=1;i<=n;i++) a[i]=in(); for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i]; for(int j=1;j<=k;j++) h[j]=1; // q[0][h[0]=t[0]=1]=0; // for(int i=1;i<=n;i++) f[i][1]=s[i]; for(int j=2;j<=k;j++) { q[j-1][h[j-1]=t[j-1]=1]=j-1; for(int i=j;i<=n;i++) { while(h[j-1]<t[j-1] && F(q[j-1][h[j-1]],i,j)<F(q[j-1][h[j-1]+1],i,j)) h[j-1]++; f[i][j&1]=F(q[j-1][h[j-1]],i,j); // cout<<i<<" "<<j<<" "<<q[j-1][h[j-1]]<<endl; while(h[j-1]<t[j-1] && (s[q[j-1][t[j-1]]]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(i,j-1)) <=(s[i]-s[q[j-1][t[j-1]-1]])*(B(q[j-1][t[j-1]-1],j-1)-B(q[j-1][t[j-1]],j-1))) t[j-1]--; q[j-1][++t[j-1]]=i; } } // for(int j=0;j<=1;j++) for(int i=1;i<=n;i++) printf("%lld%c",f[i][j]," \n"[i==n]); printf("%lld\n",f[n][k&1]); return 0; }