zoukankan      html  css  js  c++  java
  • CodeForces834D DP + 线段树

    http://codeforces.com/problemset/problem/834/D

     将一个长度为n的序列分为k段

    使得总价值最大一段区间的价值表示为区间内不同数字的个数

    n<=35000,k<=50

    这题的dp是十分显然的,用dp[i][j]表示前i个数字分成j段的最大值

    状态转移方程就是 dp[i][j] = max(dp[i - 1][k] + dis[k + 1][j] | (0 <= k <= j - 1)) 

    但是乍一想可能是个O(knn)的算法,仔细一想果然是。

    考虑线段树的优化。显然根据状态转移方程,线段树维护的是dp[i - 1][k] + dis[k + 1][j]的最大值

    也就是对每一层都build一次线段树,然后以此查询更新,时间复杂度是O(knlnn),看着十分科学

    其中一个难点在于对颜色种类的维护,dis这个35k * 35k的数组肯定是存不下的,仔细一想其实不需要什么花里胡哨的操作,用一个pre数组存储上一个这个颜色出现的地方,当遇到这个颜色的时候,在线段树pre[x] + 1,x的位置全部加上1,意在pre[x] + 1到x出现了这个颜色,种类++;

    然后整个思路就出来了,对于每一层状态,用一个build更新上一层的dp[i - 1][k],dis在查询的过程中动态更新,这种听起来就很像正解的做法一般就是正解。

    #include <map>
    #include <set>
    #include <cmath>
    #include <queue>
    #include <stack>
    #include <vector>
    #include <string>
    #include <cstdio>
    #include <cstdlib>
    #include <cstring>
    #include <sstream>
    #include <iostream>
    #include <algorithm>
    #include <functional>
    using namespace std;
    const int MAXBUF=10000;char buf[MAXBUF],*ps=buf,*pe=buf+1;
    inline bool isdigit(const char& n) {return (n>='0'&&n<='9');}
    inline void rnext(){if(++ps==pe)pe=(ps=buf)+fread(buf,sizeof(char),sizeof(buf)/sizeof(char),stdin);}
    template <class T> inline bool in(T &ans){
    #ifdef VSCode
    ans=0;T f=1;register char c;
    do{c=getchar();if ('-'==c)f=-1;}while(!isdigit(c)&&c!=EOF);
    if(c==EOF)return false;do{ans=(ans<<1)+(ans<<3)+c-48;
    c=getchar();}while(isdigit(c)&&c!=EOF);ans*=f;return true;
    #endif
    #ifndef VSCode 
    ans =0;T f=1;if(ps==pe)return false;do{rnext();if('-'==*ps)f=-1;} 
    while(!isdigit(*ps)&&ps!=pe);if(ps==pe)return false;do{ans=(ans<<1)+(ans<<3)+*ps-48;
    rnext();}while(isdigit(*ps)&&ps!=pe);ans*=f;return true;
    #endif
    }const int MAXOUT=10000;
    char bufout[MAXOUT], outtmp[50],*pout = bufout, *pend = bufout+MAXOUT;
    inline void write(){fwrite(bufout,sizeof(char),pout-bufout,stdout);pout = bufout;}
    inline void out_char(char c){*(pout++)=c;if(pout==pend)write();}
    inline void out_str(char *s){while(*s){*(pout++)=*(s++);if(pout==pend)write();}}
    template <class T>inline void out_int(T x) {if(!x){out_char('0');return;}
    if(x<0)x=-x,out_char('-');int len=0;while(x){outtmp[len++]=x%10+48;x/=10;}outtmp[len]=0;
    for(int i=0,j=len-1;i<j;i++,j--) swap(outtmp[i],outtmp[j]);out_str(outtmp);}
    template<typename T, typename... T2>
    inline int in(T& value, T2&... value2) { in(value); return in(value2...); }
    #define For(i, x, y) for(int i=x;i<=y;i++)  
    #define _For(i, x, y) for(int i=x;i>=y;i--)
    #define Mem(f, x) memset(f,x,sizeof(f))  
    #define Sca(x) scanf("%d", &x)
    #define Scl(x) scanf("%lld",&x);  
    #define Pri(x) printf("%d
    ", x)
    #define Prl(x) printf("%lld
    ",x);  
    #define CLR(u) for(int i=0;i<=N;i++)u[i].clear();
    #define LL long long
    #define ULL unsigned long long  
    #define mp make_pair
    #define PII pair<int,int>
    #define PIL pair<int,long long>
    #define PLL pair<long long,long long>
    #define pb push_back
    #define fi first
    #define se second 
    #define Vec Point
    typedef vector<int> VI;
    const double eps = 1e-9;
    const int maxn = 35010;
    const int INF = 0x3f3f3f3f;
    const int mod = 1e9 + 7; 
    int N,M,tmp,K;
    int a[maxn]; 
    int dp[maxn][55]; //以这个结尾
    int pre[maxn];
    int display[maxn];
    struct Tree{
        int l,r;
        int MAX,lazy;
    }tree[maxn * 4];
    void Pushdown(int t){
        if(tree[t].lazy){
            tree[t << 1].lazy += tree[t].lazy; tree[t << 1].MAX += tree[t].lazy;
            tree[t << 1 | 1].lazy +=  tree[t].lazy; tree[t << 1 | 1].MAX += tree[t].lazy;
            tree[t].lazy = 0;
        }
    }
    void Pushup(int t){
        tree[t].MAX = max(tree[t << 1].MAX,tree[t << 1 | 1].MAX);
    }
    void Build(int t,int l,int r,int flag){
        tree[t].l = l; tree[t].r = r;
        tree[t].lazy = 0;
        if(l == r){
            tree[t].MAX = dp[l - 1][flag];
            return;
        }
        int m = (l + r) >> 1;
        Build(t << 1,l,m,flag);
        Build(t << 1 | 1,m + 1,r,flag);
        Pushup(t);
    }
    void update(int t,int l,int r){
        if(l <= tree[t].l && tree[t].r <= r){
            tree[t].MAX++;
            tree[t].lazy++;
            return;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m) update(t << 1,l,r);
        else if(l > m) update(t << 1 | 1,l,r);
        else{
            update(t << 1,l,m);
            update(t << 1 | 1,m + 1,r);
        }
        Pushup(t);
    }
    int query(int t,int l,int r){
        if(l <= tree[t].l && tree[t].r <= r){
            return tree[t].MAX;
        }
        Pushdown(t);
        int m = (tree[t].l + tree[t].r) >> 1;
        if(r <= m){
            return query(t << 1,l,r);
        }else if(l > m){
            return query(t << 1 | 1,l,r);
        }else{
            return max(query(t << 1 | 1,m + 1,r),query(t << 1,l,m));
        }
    }
    int main()
    {
        in(N,K);
        For(i,1,N) display[i] = 0;
        For(i,1,N){
            in(a[i]);
            pre[i] = display[a[i]];
            display[a[i]] = i;
        }
        For(i,1,K){        //dp[i][j] = max(dp[i - 1][k] + dis[k + 1][j]) (0 <= k <= j - 1));
            Build(1,1,N,i - 1);
            For(j,1,N){
                update(1,pre[j] + 1,j);
                dp[j][i] = query(1,1,j);
              //  cout << dp[j][i] << " ";
            }
        //    cout << endl;
        }
        Pri(dp[N][K]);
        #ifdef VSCode
        write();
        system("pause");
        #endif
        return 0;
    }
  • 相关阅读:
    Matlab中tic和toc用法
    matlab 哪个函数可以从一组数据中随机抽取一部分出来
    matlab中rep函数的用法
    WinCE平台搭建数据库(wince6.0+vs2008+sqlce)熙熙
    熙熙如何在WinCE里上QQ(天嵌WinCE开发板,PocketPC仿真模拟器,QQ)
    数学建模方法灰色预测法
    数学建模方法层次分析法
    数学建模方法多属性决策模型
    数学建模方法Floyd算法
    数学建模方法Dijkstra算法
  • 原文地址:https://www.cnblogs.com/Hugh-Locke/p/9499724.html
Copyright © 2011-2022 走看看