zoukankan      html  css  js  c++  java
  • 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 ?
  • 相关阅读:
    Dojo初探之5:dojo的request(请求)操作、请求过程事件绑定和隐藏数据data()操作(基于dojo1.11.2版本)
    Dojo初探之4:dojo的event(鼠标/键盘)事件绑定操作(基于dojo1.11.2版本)
    为什么使用dojo?dojo与jquery有什么不同?dojo适合什么开发场景?
    Dojo初探之3:dojo的DOM操作、query操作和domConstruct元素位置操作(基于dojo1.11.2版本)
    nodejs实战:使用原生nodeJs模块实现静态文件及REST请求解析及响应(基于nodejs6.2.0版本,不使用express等webMVC框架 )
    Dojo初探之2:设置dojoConfig详解,dojoConfig参数详解+Dojo中预置自定义AMD模块的四种方式(基于dojo1.11.2)
    Dojo初探之1:AMD规范,编写符合AMD规范(异步模块加载机制)的模块化JS(其中dojo采用1.11.2版本)
    POI使用:用poi接口不区分xls/xlsx格式解析Excel文档(41种日期格式解析方法,5种公式结果类型解析方法,3种常用数值类型精度控制办法)
    Lucene全文搜索之分词器:使用IK Analyzer中文分词器(修改IK Analyzer源码使其支持lucene5.5.x)
    搭建rtmp直播流服务之4:videojs和ckPlayer开源播放器二次开发(播放rtmp、hls直播流及普通视频)
  • 原文地址:https://www.cnblogs.com/hlmark/p/4134066.html
Copyright © 2011-2022 走看看