codeforces833B The Bakery -- DP + 线段树

来源:互联网 发布:大作家软件好用吗 编辑:程序博客网 时间:2024/05/22 08:12

考虑DP。令fi,j表示前i 个盒子装前 j 个蛋糕的答案:

fi,j=max(fi1,k+vk+1,j),k[1,i1]

其中vi,j表示第 i 个蛋糕到第 j 个蛋糕装在同一个盒子里的权值。
但这样是O(n2k)的,然后我们考虑用线段树优化。
先枚举 i ,更新fi,j时用线段树记录k[1,j1]fi1,k+vk+1,j的最大值,直接更新就可以了。
时间复杂度O(nklogn)

代码:

#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>using namespace std;#define N 35010#define ll long longll c[N<<2],p[N<<2],f[2][N];int i,j,k,n,m,P[N],l[N],x;bool b;inline ll Max(ll x,ll y){    return x<y?y:x;}inline void Up(int x){    c[x]=Max(c[x<<1],c[x<<1|1]);}inline void Down(int x){    c[x<<1]+=p[x];c[x<<1|1]+=p[x];    p[x<<1]+=p[x];p[x<<1|1]+=p[x];    p[x]=0;}inline void Update1(int x,int l,int r,int y,int z){    if(l==r){        c[x]+=z;        return;    }    if(p[x])Down(x);    int Mid=l+r>>1;    if(y<=Mid)Update1(x<<1,l,Mid,y,z);else Update1(x<<1|1,Mid+1,r,y,z);    Up(x);}inline void Update(int x,int l,int r,int L,int R){    if(l>R||r<L)return;    if(l>=L&&r<=R){        c[x]++;p[x]++;        return;    }    if(p[x])Down(x);    int Mid=l+r>>1;    Update(x<<1,l,Mid,L,R);    Update(x<<1|1,Mid+1,r,L,R);    Up(x);}int main(){    scanf("%d%d",&n,&k);    for(i=1;i<=n;i++)scanf("%d",&x),P[i]=l[x],l[x]=i;    for(i=1;i<=k;i++,b^=1){        memset(c,0,sizeof(c));        memset(p,0,sizeof(p));        for(j=1;j<=n;j++){            Update(1,0,n,P[j],j-1);            Update1(1,0,n,j,f[b^1][j]);            f[b][j]=c[1];        }    }    printf("%I64d\n",f[b^1][n]);    return 0;}