• HDU 5125 magic balls(线段树+DP)


    magic balls

    Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 323    Accepted Submission(s): 90


    Problem Description
    The town of W has N people. Each person takes two magic balls A and B every day. Each ball has the volume ai and bi. People often stand together. The wizard will find the longest increasing subsequence in the ball A. The wizard has M energy. Each point of energy can change the two balls’ volume.(swap(ai,bi)).The wizard wants to know how to make the longest increasing subsequence and the energy is not negative in last. In order to simplify the problem, you only need to output how long the longest increasing subsequence is.
     
    Input
    The first line contains a single integer T(1T20)(the data for N>100 less than 6 cases), indicating the number of test cases.
    Each test case begins with two integer N(1N1000) and M(0M1000),indicating the number of people and the number of the wizard’s energy. Next N lines contains two integer ai and bi(1ai,bi109),indicating the balls’ volume.
     
    Output
    For each case, output an integer means how long the longest increasing subsequence is.
     
    Sample Input
    2
     
     
    5 3
    5 1
    4 2
    3 1
    2 4
    3 1
     
    5 4
    5 1
    4 2
    3 1
    2 4
    3 1
     
    Sample Output
    4
    4
     
     
    题意是给两个序列 a , b ..
    然后问最多用m次操作( swap(ai,bi) ),使得序列a的最长上升子序列的长度最长
    不难想出一个DP就是,dp[i][j][k] 表示最长子序列中最后一个元素是i ,用了j 次操作,k表示元素i有没进行交换(0表示无,1表示有)。
    然后转移就是
     
       dp[i][j][0] = max { dp[i][j][0] , dp[k][j][0] }  (  i = 1~ n , j = 0~i , k = 1 ~ i -1 , a[k] < a[i] ) 
       dp[i][j][0] = max { dp[i][j][0] , dp[k][j][1] }  (  i = 1~ n , j = 0~i , k = 1 ~ i -1 , b[k] < a[i] ) 
       dp[i][j][1] = max { dp[i][j][1] , dp[k][j-1][0] }  (  i = 1~ n , j = 0~i-1 , k = 1 ~ i -1 , a[k] < b[i] ) 
       dp[i][j][1] = max { dp[i][j][1] , dp[k][j-1][1] }  (  i = 1~ n , j = 0~i , k = 1 ~ i -1 , b[k] < b[i] ) 
     
    O(n)枚举状态第一维 , O(n)枚举状态第二维。
    再用线段树或者树状数组O(log n)来更新状态就行了。
    用m棵线段树,每棵线段树表示用了j次操作( j = 0~m ) 。
    每棵线段树的每个叶子结点的位置表示数值的大小,区间l~r维护的是l~r数值范围dp的最大值。
    那么先将a,b序列离散后,数值范围是0~2000。
     
    然后当我们要更新 dp[i][j][0] 的时候,就第j棵线段树找出1~a[i]-1的结点中,用dp的最大值+1 去更新。
    dp[i][j][1],就第j - 1 棵线段树找出1~b[i]-1的结点中,用dp的最大值+1 去更新。
     
    注意。假设我们已经维护出dp[i][j][k] , 先不要把状态插入线段树,因为有可能影响到dp[i][j+1][k]的更新。
    那么,在更新dp[i+1][][] 之前 , 把dp[i][][]的所有状态插进线段树就不会影响到更新了。
     
     
    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <string>
    #include <cmath>
    #include <vector>
    #include <queue>
    #include <map>
    #include <set>
    #include <stack>
    #include <algorithm>
    
    using namespace std;
    
    #define root 1,n<<1|1,1
    #define lr rt<<1
    #define rr rt<<1|1
    #define lson l,mid,rt<<1
    #define rson mid+1,r,rt<<1|1
    #define X first
    #define Y second
    typedef long long LL;
    typedef pair<int,int> pii;
    const int N = 1010 ;
    const int M = 2010 ;
    const int inf = 1e9+7;
    
    int n , m , a[N] , b[N] ;
    
    //----------------------------
    int date[N][M<<2];
    
    void Up( int id , int rt ) {
        date[id][rt] = max( date[id][lr] , date[id][rr] ) ;
    }
    
    void Build( int id , int l , int r , int rt ) {
        date[id][rt] = 0 ;
        if( l == r ) return ;
        int mid = (l+r)>>1;
        Build(id,lson),Build(id,rson);
        Up(id,rt);
    }
    
    void Update( int id , int l , int r , int rt , int x , int val ) {
        if( l == r ) {
            date[id][rt] = max( date[id][rt] , val ) ;
            return ;
        }
        int mid = (l+r)>>1;
        if( x <= mid ) Update(id,lson,x,val);
        else Update(id,rson,x,val);
        Up(id,rt);
    }
    
    int Query( int id , int l , int r , int rt , int L , int R ) {
        if( l == L && r == R ) {
            return date[id][rt];
        }
        int mid = (l+r)>>1;
        if( R <= mid ) return Query(id,lson,L,R);
        else if( L > mid ) return Query(id,rson,L,R);
        else return max( Query(id,lson,L,mid) , Query(id,rson,mid+1,R) );
    }
    //----------------------------------
    
    struct node { int x , id , xx ; }e[N<<2];
    bool cmp1( const node &a , const node &b ) { return a.x < b.x ; }
    bool cmp2( const node &a , const node &b ) { return a.id < b.id ; }
    
    void Read() {
        cin >> n >> m ;
        for( int i = 0 ; i < 2 * n ; ++i ){
            cin >> e[i].x ; e[i].id = i ;
        }
        sort( e , e + 2 * n , cmp1 );
        e[0].xx = 2 ;
        for( int i = 1 ; i < 2 * n ; ++i ){
            e[i].xx = ( e[i].x == e[i-1].x ? e[i-1].xx : e[i-1].xx + 1 );
        }
        sort( e , e + 2 * n , cmp2 );
        int tot = 0 ;
        for( int i = 1 ; i <= n ; ++i ) a[i] = e[tot++].xx , b[i] = e[tot++].xx ;
    
    }
    
    vector<pii>A,B;
    
    void Run() {
        int ans = 1 ;
        for( int i = 0 ; i <= m ; ++i ) Build( i , root );
        for( int i = 1 ; i <= n ; ++i ) {
            A.clear() , B.clear();
            for( int j = 0 ; j <= min( i , m ) ; ++j ) {
                    int tmpa = Query( j , root , 1 , a[i] - 1 ) + 1 ;
                    ans = max( ans , tmpa ) ; A.push_back(pii(j,tmpa));
                    if( !j ) continue ;
                    int tmpb = Query( j - 1 , root , 1 , b[i] - 1 ) + 1 ;
                    ans = max( ans , tmpb ) ; B.push_back(pii(j,tmpb));
                }
            for( int j = 0 ; j < A.size() ; ++j ) Update( A[j].X ,root , a[i] , A[j].Y );
            for( int j = 0 ; j < B.size() ; ++j ) Update( B[j].X ,root , b[i] , B[j].Y );
        }
        cout << ans << endl ;
    }
    
    int main()
    {
        #ifdef LOCAL
            freopen("in.txt","r",stdin);
        #endif // LOCAL
        ios::sync_with_stdio(false);
        int _ ; cin >> _ ;
        while( _-- )  Read() , Run() ;
    }
    View Code
    only strive for your goal , can you make your dream come true ?
  • 相关阅读:
    vue-cli项目打包出现空白页和路径错误问题
    Git操作手册
    Atom Editor 插件 atom-less 的使用方法
    Vue搭建
    使绝对定位高宽自适应
    原生JS表单序列化
    前端代码有关搜索引擎的代码
    网页局部打印
    万维网
    浅淡传统企业进入移动互联网的几种方式
  • 原文地址:https://www.cnblogs.com/hlmark/p/4134066.html
Copyright © 2020-2023  润新知