树状数组:
可以把数一个个插入到树状数组中, 每插入一个数, 统计比他小的数的个数,对应的逆序为 j- sum( a[j] ),其中 j 为当前已经插入的数的个数, sum( a[j] )为比 a[j] 小的数的个数,j- sum( a[j] ) 即比 a[j] 大的个数, 即逆序的个数。最后需要把所有逆序数求和,就是在插入的过程中边插入边求和。
例如
比如输入一个9 1 0 5 4的数组,那么BIT[j]树状数组的建立是在,
下标 0 1 2 3 4 5 6 7 8 9
数组 1 1 0 0 1 1 0 0 0 1
一开始的BIT是空的,每计算完一个位之后就把此位加一add(a[j], 1),所以当计算到第a[j]位时,前面的a[i]...a[0]值是1的代表存在i < j && a[i] < a[j]的数.归并:
开始把长度为n的数组a分成两个长度为n/2数组的数组b和c
因为i < j && a[i] > a[j] 的逆序数存在只有三种情况:
1、i和j 都在数组b中
2、i和j都在数组c中
3、i 在数组b 中j 在数组c中
把三种情况的逆序数加起来即可
/********************
* Author:fisty
* Data:2014-12-6
* *****************/
//求逆序数
#include <vector>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
using namespace std;
#define MAX_N 1000
typedef long long ll;
//输入
vector<int > A;
//merge
ll merge_count(vector<int> &a){
int n = a.size();
if(n <= 1) return 0;
ll cnt = 0;
//把数列a分成b和c进行分治
vector<int> b(a.begin(), a.begin()+n/2);
vector<int> c(a.begin()+n/2 , a.end());
cnt += merge_count(b); //(i,j) 在 b时
cnt += merge_count(c); //(i, j)在 c时
/*cout<< "b: ";
for(int i = 0;i < b.size(); i++)
printf("%d ", b[i]);
printf(" ");
cout << "c: ";
for(int i = 0;i < c.size(); i++)
printf("%d ", c[i]);
printf("\n");
*/
//当(i,j)横跨b, c数列时
int ai = 0, bi = 0, ci = 0;
while(ai < n){
if(bi < b.size() && (ci == c.size() || b[bi] <= c[ci])){
a[ai++] = b[bi++];
}else{
cnt += n/2 - bi;
//printf("nixu:%d \n", n/2 - bi);
a[ai++] = c[ci++];
}
}
cout << "a: ";
/*for(int i = 0;i < a.size(); i++)
printf("%d ", a[i]);
printf("\n");
*/
return cnt;
}
void solve1(){
printf("%lld\n", merge_count(A));
}
//bit
int bit[MAX_N];
int sum(int i){
int sum = 0;
while(i > 0){
sum += bit[i];
i -= i&(-i);
}
return sum;
}
void add(int i ,int x){
while(i <= MAX_N){
bit[i] += x;
i += i&(-i);
}
}
void solve2(){
memset(bit, 0, sizeof(bit));
ll ans = 0;
for(int i = 0;i < A.size(); i++){
ans += i - sum(A[i]);
add(A[i], 1);
}
printf("%lld\n", ans);
}
int main(){
int n;
scanf("%d", &n);
for(int i = 0;i < n; i++){
int t;
scanf("%d", &t);
A.push_back(t);
}
//分治法求解
solve1();
//树状数组求解
solve2();
return 0;
}