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 long
using 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]);
}