分析
如果使用冒泡排序来统计需要交换的次数的话,那么是会超时的。
思考一下,如果数组不是有序的,那么肯定存在至少两个数使得:a[i] > a[i + 1]。
那么,交换相邻两个数使得数组有序至少需要交换的次数为逆序对的数量。
证明:
假设数组中有 k 对逆序对,假设 a[i] > a[i + 1] 我们交换swap(a[i],a[i+1])swap(a[i] , a[i + 1])swap(a[i],a[i+1])那么数组中的逆序对数量只会减少一对(对 a[i] 之前的逆序对和 a[i+1] 之后的逆序对的数量没有影响),那么至少需要 k 次就可以将数组变为有序。
并且每次操作都保证会交换一组相邻的逆序对,因为当数组不是有序的时候,必定存在一组相邻的逆序对。
代码使用归并排序求逆序对数量:
#include <iostream>
using namespace std;
const int N = 500010;
int n , a[N] , temp[N];
long long res = 0;
void merge_sort(int l , int r)
{
if(l >= r) return;
int mid = (l + r) / 2;
merge_sort(l , mid) , merge_sort(mid + 1 , r);
int i = l , j = mid + 1 , k = 0;
while(i <= mid && j <= r)
{
if(a[i] <= a[j]) temp[k ++] = a[i ++];
else
{
temp[k ++] = a[j ++];
res += mid - i + 1;
}
}
while(i <= mid) temp[k ++] = a[i ++];
while(j <= r) temp[k ++] = a[j ++];
for(int i = l , j = 0; j < k; j ++ , i ++) a[i] = temp[j];
}
int main()
{
while(cin >> n , n)
{
for(int i = 0; i < n; i ++) scanf("%d" , &a[i]);
res = 0;
merge_sort(0 , n - 1);
cout << res << endl;
}
return 0;
}