斜率优化。注意要判分母为0的情况。dp数组可以滚一维。
#include<iostream> #include<cstdio> #include<cstring> #include<algorithm> #define maxn 100500 #define inf 0x7f7f7f7f7f7f7f7fLL using namespace std; long long n,k,a[maxn],sum[maxn],q[maxn],l=1,r=0,dp[2][maxn],g[maxn],ans=0; double ks(long long x,long long y) { if (sum[x]==sum[y]) return inf; return (double)(g[x]-g[y])/(sum[x]-sum[y]); } void dps() { for (long long i=1;i<=n-1;i++) { dp[1][i]=sum[i]*(sum[n]-sum[i]); g[i]=dp[1][i]-sum[n]*sum[i];ans=max(ans,dp[1][i]); } for (long long i=2;i<=k;i++) { l=r=1;q[l]=i-1; for (long long j=i;j<=n-1;j++) { while ((r-l) && (ks(q[l],q[l+1])>=-sum[j])) l++; dp[i&1][j]=dp[(i&1)^1][q[l]]+(sum[n]-sum[j])*(sum[j]-sum[q[l]]); ans=max(ans,dp[i&1][j]); while ((r-l) && (ks(q[r-1],q[r])<ks(q[r],j))) r--; q[++r]=j; } for (long long j=i;j<=n-1;j++) g[j]=dp[i&1][j]-sum[n]*sum[j]; } } int main() { scanf("%lld%lld",&n,&k); for (long long i=1;i<=n;i++) {scanf("%lld",&a[i]);sum[i]=sum[i-1]+a[i];} dps(); printf("%lld\n",ans); return 0; }