zoukankan      html  css  js  c++  java
  • 逆序对 (树状数组 | | 归并排序

    数组前面的一个元素 大于等于 后面的一个元素就是一个逆序对;

    树状数组可以快速求前缀和,利用这一特性,可以求逆序对个数,见下:

    用数组c[ i ]记录数组a[ n ]中i这一元素出现的次数 ,当a[ n ]中元素较大时可以离散化处理。

    将a[ n ]从a[n -1]到a[0] 依次存到树状数组中,每存一个,对存的元素i求一次c[i]的前缀和, 这就是当前已扫描过的比i小的元素的个数,由于a[n]是倒着扫描的,所以此时比i小的元素都对应一个逆序对,统计之。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    int c[600000];
    
    int a[600000] ,b[600000];
    int n;
    long long ans;
    
    
    int lowbit( int x){
        return x & ( -x);
    }
    
    void updata( int x ,int v){
         while( x<=n){
             c[x] += v;
             x += lowbit( x);
         }
    }
    
    int getsum( int x){
         int s=0;
         while( x>0){
             s += c[ x];
             x -= lowbit( x);
         }
         return s;
    }
    
    int main( ){
         while( ~scanf( "%d" ,&n) ,n){
             memset( c ,0 ,sizeof( c ));
             for( int i=0 ;i<n ;i++){
                 scanf( "%d" ,&a[i]);
                 b[i] = a[i];
             }
             sort( b ,b + n);                        //离散化处理
             int sz = unique( b ,b+n) - b;
             ans = 0;
             for( int i=n-1 ;i >=0  ;i--){
                 int t = lower_bound( b ,b+sz ,a[i]) -b +1;  //搜索对应的元素下标
                 ans += getsum( t) ;
                 updata( t, 1);
             }
             printf( "%lld
    " ,ans);
         }
         return 0;
    }

    归并排序求逆序对在lrj的高效算法设计一章学过,不过又把一些细节忘了:

    1) 分治的参数x,y是左闭右开的,就是(n-1是数组末项下标 (0,n)->( 0,m ),(m ,n )

    2)  分治条件y-x>1,因为y是开的,碰不到,y-x==1就是只有一个元素不能再分的情况了

    3) 求逆序对时是 cnt += m-p,有半部分有一个小的左半部分没排的(m-p个)都是比他大的

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    using namespace std;
    
    int a[600000];
    int b[600000];
    int n;
    long long ans;
    
    void ergesort( int x ,int y){
       //  cout << x<<' '<<y<<endl;
         if( y - x <= 1)return;
         int m = x + (y - x)/2;
         ergesort( x ,m) ;
         ergesort( m ,y) ;
         int p = x, q =m ,i=x;
    
         while ( p < m || q < y){
             if( q >=y || p<m && a[p] < a[q]) b[i++] = a[p++];
             else b[i++] = a[q++] ,ans+= m-p;
         }
         for( int i=x ; i<y ;i++) a[ i] = b[ i];
         return ;
    }
    
    int main( ){
         while( ~scanf( "%d" ,&n) ,n){
                ans=0;
             for( int i=0 ;i<n ;i++){
                scanf( "%d" ,&a[i]);
             }
             ergesort( 0 ,n);
      //   for( int i=0 ;i<n ;i++)printf("%d ",a[i]);
             printf( "%lld
    ",ans);
         }
         return 0;
    }
  • 相关阅读:
    微信小程序如何获取openid
    js经典试题之常用的方法
    js经典试题之运算符的优先级
    js如何使浏览器允许脚本异步加载
    es6从零学习(五):Module的语法
    es6从零学习(四):Class的继承
    js如何处理字符串中带有↵字符
    Zuul中聚合Swagger的坑
    阿里Sentinel支持Spring Cloud Gateway啦
    Spring Boot中的Mongodb多数据源扩展
  • 原文地址:https://www.cnblogs.com/-ifrush/p/10703791.html
Copyright © 2011-2022 走看看