bzoj3675: [Apio2014]序列分割

来源:互联网 发布:php社交系统 编辑:程序博客网 时间:2024/06/07 07:16

bzoj3675: [Apio2014]序列分割
二维斜率优化DP。


题解

首先手算一下就会发现,对于某种分割方法,计算顺序不影响结果。既然这样可以简化成简单DP。考虑f[i][j]表示前i个数分割j次的最大值,s[i]维护从1到i的前缀和,则f[i][j]=min(f[k][j-1]+s[k]*(s[i]-s[k]))。上斜率优化即可。另外,因为0会导致点重合,所以输入的时候忽略0。


代码

#include<iostream>#include<cstdio>#define mxn 100005#define LL long longusing namespace std;int q[mxn][2],i,k,h=1,t,t2,pre,n,now=1;LL g[mxn][2],d[mxn][2],s[mxn],tp;LL mul(LL y1,LL y2,LL x1,LL x2){return x1*y2-x2*y1;}int main(){    scanf("%d%d",&n,&k);    while(n--)    {        scanf("%lld",&tp);        if(tp){q[++t][0]=t,s[t]=tp+s[t-1],g[t][0]=s[t]*s[t];}    }    n=t;    while(k--)    {        for(i=1;i<=n;i++)        {            while(h<t&&q[h+1][pre]<i&&g[h+1][pre]-g[h][pre]<s[i]*(s[q[h+1][pre]]-s[q[h][pre]]))            h++;            tp=q[h][pre];            d[i][now]=d[tp][pre]+s[tp]*(s[i]-s[tp]);            tp=s[i]*s[i]-d[i][now];            while(t2&&mul(tp-g[t2-1][now],g[t2][now]-g[t2-1][now],            s[i]-s[q[t2-1][now]],s[q[t2][now]]-s[q[t2-1][now]])>0)t2--;            g[++t2][now]=tp,q[t2][now]=i;        }        swap(now,pre),t=t2,t2=0,h=1;    }    printf("%lld\n",d[n][pre]);}
0 0