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\n",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\n",ans);

    }

    return 0;

}

 

你可能感兴趣的:(poj)