设为首页 加入收藏

TOP

HDU 1394 Minimum Inversion Number(线段树求逆序对数目)
2015-11-21 00:54:33 来源: 作者: 【 】 浏览:1
Tags:HDU 1394 Minimum Inversion Number 线段 数目

HDU 1394

题意:

给一个由0~n-1组成的序列,求出该序列的所有循环同构序列中的最小逆序对数目,逆序对的两个元素可以不相邻。

思路:

这题据说可以直接暴力 O(n2) 可以水过。。
说一下线段树做法 O(nlogn) :
以这个序列来说明:
1,9,2,3,0,8,5,7,4,6

我们先假设有一个长度为n元素全为0的数组:
0,0,0,0,0,0,0,0,0,0

我们先计算所给序列的第一项1(实际上是第0项)的数字所对应位置之后所有元素的和(括号里面的数),和就是当前与这个数逆序的数的个数,这样做避免了重复统计逆序对,我们把它累计起来:
0,(0,0,0,0,0,0,0,0,0),sum+=0;

我们将所给序列的第一项的数字所对应位置置1:
0,1,0,0,0,0,0,0,0,0

第二项9:
0,1,0,0,0,0,0,0,0,(0),sum+=0;

0,1,0,0,0,0,0,0,0,1

第三项2:
0,1,(0,0,0,0,0,0,0,1),sum+=1;
(2与9逆序)
0,1,1,0,0,0,0,0,0,1

第四项3:
0,1,1,(0,0,0,0,0,0,1),sum+=1;
(3与9逆序)
0,1,1,1,0,0,0,0,0,1

第五项0:
(0,1,1,1,0,0,0,0,0,1),sum+=4;
(0与1,2,3,9逆序)
1,1,1,1,0,0,0,0,0,1

以此类推到最后,sum便是该序列逆序对个数。

现在考虑循环同构序列的最小值:

刚才的序列:
1,9,2,3,0,8,5,7,4,6

我们把x0 = 1移到最后:
9,2,3,0,8,5,7,4,6,1

发现逆序对增加了8对(8 = 10 - x0 - 1),减少了1对(1 = x0),可以推出结论,向后移动一个数字,逆序对增加n - xi - 1,减少xi。扫一遍维护最小值即可。

代码:

/*
* @author FreeWifi_novicer
* language : C++/C
*/
#include
   
     #include
    
      #include
     
       #include
      
        #include
       
         #include
        
          #include
         
           #include
           #include
           
             #include
            
              #include
             
               using namespace std; #define clr( x , y ) memset(x,y,sizeof(x)) #define cls( x ) memset(x,0,sizeof(x)) #define mp make_pair #define pb push_back #define lson l , mid , rt << 1 #define rson mid + 1 , r , rt << 1 | 1 typedef long long lint; typedef long long ll; typedef long long LL; const int maxn = 5000 + 50 ; int sum[ 4 * maxn ]; void push_up( int rt ){ sum[rt] = sum[ rt << 1 ] + sum[ rt << 1 | 1 ] ; } void update( int pos , int l , int r , int rt ){ if( pos == l && pos == r ){ sum[rt] ++ ; return ; } int mid = ( l + r ) / 2 ; if( pos <= mid ) update( pos , lson ) ; else update( pos , rson ) ; push_up( rt ) ; } int query( int ql , int qr , int l , int r , int rt ){ if( ql > r || qr < l ) return 0 ; if( ql <= l && qr >= r ) return sum[rt] ; int res = 0 ; int mid = ( l + r ) / 2 ; if( ql <= mid ) res += query( ql , qr , lson ) ; if( qr > mid ) res += query( ql , qr , rson ) ; return res ; } int x[maxn] ; int main(){ //freopen(input.txt,r,stdin); int n ; while( cin >> n ){ cls( sum ) ; cls( x ) ; int tmp = 0 ; for( int i = 0 ; i < n ; i++ ){ scanf( %d , &x[i] ) ; tmp += query( x[i] , n - 1 , 0 , n - 1 , 1 ) ; update( x[i] , 0 , n - 1 , 1 ) ; } int ans = tmp ; for( int i = 0 ; i < n ; i++ ){ tmp += ( n - x[i] - 1 ) ; tmp -= x[i] ; ans = min( ans , tmp ) ; } printf( %d , ans ) ; } return 0; } 
             
            
           
         
        
       
      
     
    
   

?

】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
分享到: 
上一篇UVA 12716 GCD XOR(数论+枚举+打.. 下一篇LeetCode -- Remove Invalid Pare..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容: