利用归并排序计算逆序对
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <algorithm>
#include <stack>
using namespace std;
long long ans;
int a[1000000];
void merge(int *a , int first, int mid, int last)
{
int * temp = new int[last - first + 1];
int first1 = first, last1 = mid;
int first2 = mid + 1, last2 = last;
int index = 0;
while(first1 <= last1 && first2 <= last2)
{
if(a[first1 ] <= a[first2])
{
temp[index++] = a[first1++];
}
else
{
ans += last1 - first1 + 1;
temp[index++] = a[first2++];
}
}
while(first1 <= last1)
{
temp[index++] = a[first1++];
}
while(first2 <= last2)
{
temp[index++] = a[first2++];
}
int i;
for(i = first; i <= last; i++)
{
a[i] = temp[i - first];
}
delete [] temp;
return;
}
void inv_pair(int *a, int first, int last)
{
if(last - first > 0)
{
int mid = (last + first) / 2;
inv_pair(a, first, mid);
inv_pair(a, mid + 1, last);
merge(a, first, mid, last);
}
return;
}
int main()
{
int n, i;
while(cin >> n)
{
ans = 0;
for(i = 0; i < n; i++)
cin >> a[i];
inv_pair(a, 0, n - 1);
cout << ans << endl;
}
return 0;
}
这里就一个操作可能不太好理解,对于从大到小排列数组a,如果a[first1]这个元素大于a[first2](形成一个逆序数对), 那么a[first1] 到 a[last1]的全部元素都会大于a[first2](形成 `last1-first1+1`个逆序数对)。
如图:
2019.2.20补充:
在上述方法中,计算逆序数时要统计的是从first1到last1的元素个数(last1-first1+1)。
那么,当a[first1]>a[first2]时,能不能统计从first2到(mid+1)的元素个数(first2-(mid+1)+1)呢?
答案是不行的,这样的话,可能会重复统计某些逆序对。
举例来说,当a[first1]>a[first2]时,我们统计了逆序对{(first1, mid+1), (first1, mid+2), ..., (first1, first2-1) 以及 (first1, first2) }。
现在假设a[first1]>a[first2+1],那么我们会统计逆序对{(first1, mid+1), (first1, mid+2), ..., (first1, first2-1), (first1, first2) 以及(first1, first2+1) }, 此时的统计跟之前有重复,这样统计出来的逆序数就比正确的值要大。
2018.2.21补充 迭代版本的计算逆序对
#include <iostream>
#include <vector>
using namespace std;
// 通过 https://vjudge.net/problem/HihoCoder-1524
unsigned long long merge_sort(vector<int>& arr){
unsigned long long cnt = 0;
int n = arr.size();
if(n <= 1) return 0;
vector<int> tmp(n);
int ls, le, rs, re, id;
for(int i = 1; i < n; i <<= 1){
for(int index = 0; index+i<n; index += (i<<1)){
id = 0, ls = index, le = index+i-1, rs = le+1, re = min(le+i, n-1);
while(ls <= le && rs <= re){
if(arr[ls] <= arr[rs]) tmp[id++] = arr[ls++];
else {
tmp[id++] = arr[rs++];
cnt += (le-ls+1);
}
} while(ls <= le){ // enter this loop when rs = re+1
arr[--rs] = arr[le--];
} while(id > 0){ // end this loop when id == 0
arr[--rs] = tmp[--id];
}
}
} return cnt;
}
void print(vector<int> v){
for(int i = 0; i < v.size(); ++i){
cout << v[i] << ' ';
} cout << endl;
}
void check(vector<int> v){
for(int i = 1; i < v.size(); ++i){
if(v[i-1] > v[i]){
cout << "sort failed" << endl;
return;
}
} cout << "sort succeed" << endl;
}
void f(){
/* 验证 */
int n = 100, a[] = {364,637,341,406,747,995,234,971,571,219,993,407,416,366,315,301,601,650,418,355,460,505,360,965,516,648,727,667,465,849,455,181,486,149,588,233,144,174,557,67,746,550,474,162,268,142,463,221,882,576,604,739,288,569,256,936,275,401,497,82,935,983,583,523,697,478,147,795,380,973,958,115,773,870,259,655,446,863,735,784,3,671,433,630,425,930,64,266,235,187,284,665,874,80,45,848,38,811,267,575};
vector<int> v(a, a+n);
int cnt = merge_sort(v);
print(v);
check(v);
cout << "True answer is " << 2519 << endl;
cout << "My answer is " << cnt << endl;
}
int arr[100000];
int main(){
int n;
while(cin >> n){
for(int i = 0; i < n; ++i) cin >> arr[i];
vector<int> v(arr, arr+n);
cout << merge_sort(v) << endl;
}
return 0;
}