求一个数组的逆序数
因为数据较大所以不能用冒泡排序
这里用到归并排序...到现在不看书还是写不出来
注意这里在归并排序过程中求逆序数个数的方法!
证明如下:
对于当前两个数组,a和b分别有序
合并a[i] b[j]的过程中我们这样考虑逆序数的个数:
如果a[i] > b[j],则a[i]后面的数必然都大于b[j],针对b[j]逆序数为a[i]后面数的个数,即len(a)-i+1
如果a[j] <= b[j], 则a[i]后面的数与b[j]的大小关系无法判断,我们只能接着判断a[i+1]和b[j]的关系
而针对b中每个元素的逆序数之和必然为总的逆序数
代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 500010
#define LL long long
using namespace std;
int a[MAXN],tmp[MAXN];
LL ans;
void merge(int L, int R, int M) {
int i, j, k = 1;
for(i=L,j=M+1; i<=M&&j<=R; ) {
if(a[i] < a[j]) {
tmp[k++] = a[i++];
}
else {
tmp[k++] = a[j++];
ans += M-i+1;
}
}
for( ; i<=M; )
tmp[k++] = a[i++];
for( ; j<=R; )
tmp[k++] = a[j++];
for(i=1; i<k; ++i)
a[L+i-1] = tmp[i];
}
void mergesort(int front, int end) {
if(front < end) {
mergesort(front, (front+end)/2);
mergesort((front+end)/2+1, end);
merge(front, end, (front+end)/2);
}
}
int main(void) {
int n;
while(scanf("%d", &n) && n) {
ans = 0;
for(int i=1; i<=n; ++i) {
cin >> a[i];
}
mergesort(1, n);
cout << ans << endl;
}
return 0;
}
树状数组做法:
如输入val:9 1 0 5 4
则这五个数对应下标依次为pos:1 2 3 4 5
把输入的五个数联合下标进行排序得到:
val:0 1 4 5 9
pos:3 2 5 4 1
再令r[pos[i]] == i
此时有:
下标: 1 2 3 4 5
val: 0 1 4 5 9
r: 1 2 3 4 5//此时val和r中元素相对大小关系相同
pos: 3 2 5 4 1
得到:
下标i==r[pos[i]]: 1 2 3 4 5
pos: 3 2 5 4 1
可以发现此时r数组中的数值相对大小关系和val数组中相对大小关系相同
但是数值之间变得更加紧凑!这就使得我们缩小了所使用数组的范围,节省了空间;这叫做离散化操作
接下来我们只要找到r数组的逆序数即可
顺序访问r并执行树状数组add(r[i], 1)操作
则执行树状数组sum(r[i])返回小于等于r[i]的数的个数
i表示当前数组中插入的数的个数
则i-sum(r[i])即为1-i这些下标存放数中大于r[i]的数个数
代码如下:
#include <cstdio>
#include <iostream>
#include <algorithm>
#define MAXN 500010
#define LL long long
using namespace std;
struct Node {
int val, pos;
}node[MAXN];
int r[MAXN],c[MAXN], n;
LL ans;
bool cmp(Node a, Node b) {
return a.val < b.val;
}
int lowbit(int x) {
return (-x)&x;
}
int sum(int x) {
int sum = 0;
while(x > 0) {
sum += c[x];
x -= lowbit(x);
}
return sum;
}
void add(int x) {
while(x <= n) {
c[x]++;
x += lowbit(x);
}
}
int main(void) {
while(scanf("%d", &n) && n) {
ans = 0;
for(int i=1; i<=n; ++i) {
scanf("%d", &node[i].val);
node[i].pos = i;
}
sort(node+1, node+n+1, cmp);
for(int i=1; i<=n; ++i) {
r[node[i].pos] = i;
c[i] = 0;
}
for(int i=1; i<=n; ++i) {
add(r[i]);
printf("\n----------%d:\n", i);
for(int j=1; j<=n; ++j)
printf("%d\t", c[j]);
printf("--------%d\n", i-sum(r[i]));
ans += i-sum(r[i]);
}
cout << ans << endl;
}
return 0;
}