• Codeforces Round #426 (Div. 2)


    题目链接:http://codeforces.com/contest/834/problem/D

    题意:给定一个长度为n的序列和一个k,现在让你把这个序列分成刚好k段,并且k段的贡献之和最大。对于每一段的贡献为该段有多少个不同的数字。

    思路:考虑dp, dp[k][i]表示前i个数切k段的答案,那么dp[k][i]=max(dp[k-1][j]+color(j+1,i)) [1<=j<i], [color(l,r)表示区间[l,r]有多少个不同的数字] ,由于第k行的dp值只会影响到k+1行的dp值,所以我们可以把k这一维忽略掉。考虑转移dp[k][i+1],新增加的i+1这个点会影响到[pre[a[i]]+1,i]这段区间+1。

    ftiasch的题解

    我们在建线段树的时候,树上的结点(结点表示的区间为[l,r])维护的是g[k](即dp[k-1][r-1]),然后就是区间加和区间最大值了。

    #include <iostream>
    #include <cstdio>
    #include <cmath>
    #include <queue>
    #include <cstring>
    #include <algorithm>
    #include <map>
    #include <string>
    #include <bitset>
    using namespace std;
    typedef long long LL;
    const int MAXN = 35000 + 24;
    
    int n,k,pre[MAXN],dp[MAXN];
    struct Color{
        int val,l,r;
    }c[MAXN];
    
    //Segment Tree
    #define L(x)(x<<1)
    #define R(x)(x<<1|1)
    struct Node{
        int l,r,Lazy,maxval;
        Node(int _l=0,int _r=0,double _val=0){
            l=_l; r=_r; maxval=_val;
        }
    }Seg[MAXN*4];
    void pushUp(int k){
        Seg[k].maxval=max(Seg[L(k)].maxval,Seg[R(k)].maxval);
    }
    void pushDown(int k){
        if(Seg[k].Lazy){
            Seg[L(k)].Lazy+=Seg[k].Lazy;
            Seg[L(k)].maxval+=Seg[k].Lazy;
            Seg[R(k)].Lazy+=Seg[k].Lazy;
            Seg[R(k)].maxval+=Seg[k].Lazy;
            Seg[k].Lazy=0;
        }
    }
    void Build(int st,int ed,int k){
        Seg[k].l=st; Seg[k].r=ed; Seg[k].Lazy=0;
        if(st==ed){
            Seg[k].maxval=dp[st-1];
            return;
        }
        int mid=(st+ed)>>1;
        Build(st,mid,L(k)); Build(mid+1,ed,R(k));
        pushUp(k);
    }
    void Modify(int st,int ed,int k,int val){
        if(Seg[k].l==st&&Seg[k].r==ed){
            Seg[k].maxval+=val;
            Seg[k].Lazy+=val;
            return;
        }
        pushDown(k);
        if(Seg[L(k)].r>=ed){
            Modify(st,ed,L(k),val);
        }else if(Seg[R(k)].l<=st){
            Modify(st,ed,R(k),val);
        }else{
            Modify(st,Seg[L(k)].r,L(k),val); Modify(Seg[R(k)].l,ed,R(k),val);
        }
        pushUp(k);
    }
    int Query(int st,int ed,int k){
        if(Seg[k].l==st&&Seg[k].r==ed){
            return Seg[k].maxval;
        }
        pushDown(k);
        int res;
        if(Seg[L(k)].r>=ed){
            res=Query(st,ed,L(k));
        }else if(Seg[R(k)].l<=st){
            res=Query(st,ed,R(k));
        }else{
            res=max(Query(st,Seg[L(k)].r,L(k)),Query(Seg[R(k)].l,ed,R(k)));
        }
        pushUp(k);
        return res;
    }
    int main(){
    #ifdef kirito
        freopen("in.txt","r",stdin);
        freopen("out.txt","w",stdout);
    #endif
        while(~scanf("%d%d",&n,&k)) {
            memset(pre,0,sizeof(pre));
            for(int i=1;i<=n;i++){ 
                scanf("%d",&c[i].val);
                c[i].r=i; c[i].l=pre[c[i].val]+1; pre[c[i].val]=i;
            }
            for(int i=1;i<=n;i++){
                dp[i]=dp[i-1]+(c[i].l==1?1:0);
            }
            for(int j=2;j<=k;j++){
                Build(1,n,1);
                for(int i=1;i<=n;i++){
                    Modify(c[i].l,c[i].r,1,1);
                    dp[i]=Query(1,i,1);
                }
            }
            printf("%d
    ",dp[n]);
        }
        return 0;
    }
  • 相关阅读:
    【转】size_t和ssize_t
    WCF订票系统DEMO
    VS2008显示解决方案的方法
    一些好用的开源控件
    SQL 的Over 子句
    Sql2005高效分页语句
    使用winform的showdialog小心内存泄漏
    字符串连接类(Javascript)
    SharpZipLib 的使用
    浅谈持久化
  • 原文地址:https://www.cnblogs.com/kirito520/p/7264304.html
Copyright © 2020-2023  润新知