给定一个整数数组A,如果对于
i != j && i < j && A[i] > A[j]
就称i和j为一个逆序对。使用分治思想改写归并排序算法是最容易理解的O(nlog(n))的求逆序对的算法。使用BIT也可以达到O(nlog(n)),但是难以理解一些。先把代码贴在这里:
const int MAX_N = 1000;
int bit[MAX_N + 1], n;
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 a[4] = { 3, 2, 1, 4 };
void solve() {
ll ans = 0;
for (int j = 0; j < n; j++) {
ans += j - sum(a[j]);
add(a[j], 1);
}
cout << ans << endl;
}
对于BIT不了解的读者可以找一本书先了解一下,这里的代码来自于《挑战程序设计竞赛》。我们这里仅仅解释为什么main函数里的逻辑可以求得逆序对。首先我们看到在for循环结束前a[j]加了一,那么如果数组A完全是顺序排列的,我们可以预料到下一次循环,sum(a[1])的结果应该为一。但是如果出现了一个逆序对,我们会发现a[1]的值仍然为零,这时j-sum(a[j])的值就是j之前的逆序对的数量。所以for循环之后我们就得到了位置0,1,...,n-1之前的所有逆序对的和,就是答案。但是我们发现如果我们的数组不是1,2,...,n取值的,我们必须先进行处理。比如[5, 6, 2, 8],要被normalize成为[3,2,1,4]才可以。但是使用归并排序的算法计算逆序对是不需要normalize的。