• poj 2299 逆序数


    http://poj.org/problem?id=2299

    坑:答案是long long 输出……!!!!!

    题意是:求一个数组进行冒泡排序交换的次数

    题解:求逆序数

    题解Ⅰ:

    归并排序求逆序数

    归并排序求逆序数之前写过

    1.归并排序是把两个有序的数组合并成为一个有序的数组,利用分治的思想就可以进行排序

      逆序数可以利用这个思想求

      求出第一个数组的逆序数,和第二个数组的逆序数,再将两个数组整体的逆序数求出来

      f(x,y) = f(x,mid) + f(mid,y) + 之后数组的逆序数

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    #include <vector>
    #include <map>
    #include <queue>
    #include <stack>
    const int MAXN =  500000 + 10;
    const int INF = 0x7fffffff;
    const int MOD = 1000007;
    const double ESP = 10e-8;
    const double Pi = acos(-1.0);
    typedef long long LL;
    using namespace std;
    LL a[MAXN];
    LL b[MAXN];
    LL h(int s,int e){
        if(e-s <= 1){
            return 0;
        }
        int mid = s + (e-s)/2;
        LL x = h(s,mid);
        LL y = h(mid,e);
        int p1 = s;
        int p2 = mid;
        int p3 = s;
        LL cnt = 0;
        while(p1 < mid || p2 < e){
            if(p2 >= e || (p1 < mid && a[p1] < a[p2])){
                b[p3++] = a[p1++];
            }
            else{
                b[p3++] = a[p2++];
                cnt += (mid-p1); /*第二个数组当前元素比第一个数组当前元素小,所以第一个数组从当前元素到最后的元素都比第二个数组的大(数组一,二都已经有序了),所以第一个数组结尾下标,减去第一个数组的当前元素就是两个数组的逆序数*/
            }
        }
        for(int i = s;i < e;i++){
            a[i] = b[i];
        }
        return x+y+cnt;
    }
    int main(){
        //freopen("input.txt","r",stdin);
        int n;
        while(~scanf("%d",&n) && n){
            for(int i = 0;i < n;i++){
                scanf("%d",&a[i]);
            }
            LL ans = h(0,n);
            printf("%lld
    ",ans);
        }
        return 0;
    }

    题解Ⅱ:

    http://www.cnblogs.com/shenshuyang/archive/2012/07/14/2591859.html

    这个童鞋写得已经很棒了
    1.数组元素太大,而n 的个数又很少,所以需要离散化

    离散化:

    用struct Node{

      int v;

      int order;

    };

    将元素读入,并且将元素的次序读入

    将元素排序之后,下标的标号一定程度上是代表元素的大小

    所以用下标的标号就可以表示元素

    这样范围就减少了

    2.

    树状数组是求 前 i 个 元素的和

    先 add(a[i],1)

    再 i - sum(a[i]) 

    前面已经有 i 个元素了,sum(a[i]) 表示 1 - a[i] 的和 ,而 i - sum(a[i])  表示有多少个数字比 a[i] 大 但是 次序却在 i 位置的前面  就是 a[i] 元素的逆序数

    #include <iostream>
    #include <cstring>
    #include <cstdio>
    #include <cstdlib>
    #include <cmath>
    #include <algorithm>
    #include <cstdlib>
    #include <vector>
    #include <map>
    #include <queue>
    #include <stack>
    const int MAXN =  500000 + 10;
    const int INF = 0x7fffffff;
    const int MOD = 1000007;
    const double ESP = 10e-8;
    const double Pi = acos(-1.0);
    typedef long long LL;
    using namespace std;
    int a[MAXN];
    int bit[MAXN+1];
    int n;
    struct Node{
        int v;
        int order;
        bool operator < (const Node x)const{
            return v < x.v;
        }
    };
    Node in[MAXN];
    int sum(int i){
        int s = 0;
        while(i>0){
            s += bit[i];
            i -= (i & -i);
        }
        return s;
    }
    void add(int i,int x){
        while(i <= n){
            bit[i] += x;
            i += (i&-i);
        }
    }
    int main(){
    //    freopen("input.txt","r",stdin);
        while(~scanf("%d",&n) && n){
            memset(bit,0,sizeof(bit));
            for(int i = 1;i <= n;i++){
                scanf("%d",&in[i].v);
                in[i].order = i;
            }
            sort(in+1,in+1+n);
            for(int i = 1;i <= n;i++){
                a[in[i].order] = i;
            }
            LL ans = 0;
            for(int i = 1;i <= n;i++){
                add(a[i],1);
                ans += i-sum(a[i]);
            }
            printf("%lld
    ",ans);
        }
        return 0;
    }
  • 相关阅读:
    最受欢迎的北大通选课导读·1[精品]
    社会保险,
    养老金的计算,
    毫秒 后的一个计算,
    返回格式 的数据结构再次改造,
    阶段状态池子,
    生活,-摘
    融合,
    tableview 也可以实现这个效果,
    字体大小 一致起来,
  • 原文地址:https://www.cnblogs.com/hanbinggan/p/4545457.html
Copyright © 2020-2023  润新知