BZOJ 3675 序列分割

Posted on 2016-12-26 13:06  ziliuziliu  阅读(140)  评论(0编辑  收藏  举报

斜率优化。注意要判分母为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;
}