zoukankan      html  css  js  c++  java
  • CF 833B

    互测题T3...

    首先有个dp是非常好想的:

    设dp[i][j]为前j个数分成i组的最大得分,则易得:dp[i][j]=max{dp[i-1][k-1]+num[k][j]},其中,num[k][j]表示从第k个数到第j个数不同值的数量

    而num数组可以预处理出来,时间复杂度O(n^2 k)

    等等,这样好像过不掉这道题啊

    我们发现,max{dp[i-1][k-1]+num[k][j]}这个东西是不是应该用什么维护一下?

    线段树!

    利用线段树,我们可以实现区间求最值!

    我们记录一个位置i上的数a[i]上一次出现的位置为las[i],那么当我们更新dp到位置i时,我们就可以进行转移,而如果一共分了k组,则最后这一组的起点一定在k以后!

    同时,利用las[i],我们可以将las[i]+1~i这一整段区间的值全部+1,因为这一段区间在更新dp时不产生重复

    最后我们在k~i这段区间上做区间查询,求最大值即为dp值

    每次更新完一组的dp值以后,都需要重新建树,类似滚动数组的原理

    还有,在建树时,考虑到转移方程中需要用到的是dp[i-1][k-1],所以在建树时赋值的下标都应当-1以便利用

    代码:

    #include <cstdio>
    #include <cmath>
    #include <cstring>
    #include <cstdlib>
    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <stack>
    #define rt1 rt<<1
    #define rt2 (rt<<1)|1
    #define ls tree[rt].lson
    #define rs tree[rt].rson
    using namespace std;
    struct Tree
    {
        int lson;
        int rson;
        int maxval;
        int lazy;
    }tree[400005];
    int dp[55][35005];
    int las[35005];
    int p[35005];
    int n,k;
    void buildtree(int l,int r,int rt,int typ)
    {
        ls=l;
        rs=r;
        tree[rt].lazy=0;
        if(l==r)
        {
            tree[rt].maxval=dp[typ][l-1];
            return;
        }
        int mid=(l+r)>>1;
        buildtree(l,mid,rt1,typ);
        buildtree(mid+1,r,rt2,typ);
        tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval);
    }
    void pushdown(int rt)
    {
        int t=tree[rt].lazy;
        tree[rt].lazy=0;
        tree[rt1].lazy+=t;
        tree[rt2].lazy+=t;
        tree[rt1].maxval+=t;
        tree[rt2].maxval+=t;
    }
    void ins(int l,int r,int v,int rt)
    {
        if(ls>r||rs<l)
        {
            return;
        }
        if(ls>=l&&rs<=r)
        {
            tree[rt].lazy+=v;
            tree[rt].maxval+=v;
            return;
        }
        pushdown(rt);
        int mid=(ls+rs)>>1;
        if(l<=mid)
        {
            ins(l,r,v,rt1);
        }
        if(r>mid)
        {
            ins(l,r,v,rt2);
        }
        tree[rt].maxval=max(tree[rt1].maxval,tree[rt2].maxval);
    }
    int query(int l,int r,int rt)
    {
        if(l>rs||r<ls)
        {
            return 0;
        }
        if(l<=ls&&r>=rs)
        {
            return tree[rt].maxval;
        }
        pushdown(rt);
        return max(query(l,r,rt1),query(l,r,rt2));
    }
    int main()
    {
    //    freopen("handsome.in","r",stdin);
    //    freopen("handsome.out","w",stdout);
        scanf("%d%d",&n,&k);
        for(int i=1;i<=n;i++)
        {
            int x;
            scanf("%d",&x);
            las[i]=p[x];
            p[x]=i;
        }
        buildtree(1,n,1,0);
        for(int i=1;i<=k;i++)
        {
            for(int j=1;j<=n;j++)
            {
                int lq=las[j];
                ins(lq+1,j,1,1);
                dp[i][j]=query(i,j,1);
            }
            buildtree(1,n,1,i);
        }
        printf("%d
    ",dp[k][n]);
        return 0;
    }
  • 相关阅读:
    递归方法:对于树形结构的表,根据当前数据获取无限极的父级名称
    P
    A
    今年暑假不AC1
    J
    今年暑假不AC
    A
    *max_element函数和*min_element函数
    1199: 房间安排
    素数
  • 原文地址:https://www.cnblogs.com/zhangleo/p/9736344.html
Copyright © 2011-2022 走看看