求解逆序对的个数关键在于利用分治法,将数组分成三段,分别求解在左半段内部的逆序对个数和右半段逆序对的个数,最后,在左半端和右半段排序完成后,两边合二为一的时候又有多少逆序对,解决思想与归并排序相同,只不过要加上计算逆序对的步骤。
#include<iostream>
using namespace std;
typedef long long LL;
const int maxn = 1e6 + 5;
int num[maxn];
int t[maxn];
LL merge_sort(int l, int r)
{
if (l == r)
{
return 0;
}
else
{
LL ans = 0;
int mid = (l + r) >> 1;
ans += merge_sort(l, mid), ans += merge_sort(mid + 1, r);
int i = l, j = mid + 1, k = 0;;
while (i <= mid && j <= r)
{
if (num[i] <= num[j])
{
t[k++] = num[i++];
}
else
{
t[k++] = num[j++];
ans += mid - i + 1;//在左右两边都已经排序完成的情况下,对
//于下标为i的数,i-->mid这段区间的数一定都比下标为j的数大,那么这些数一定可
//以与j形成逆序对.
}
}
while (i <= mid)t[k++] = num[i++];
while (j <= r)t[k++] = num[j++];
for (int i = l, j = 0; i <= r; i++, j++)
{
num[i] = t[j];
}
return ans;
}
}
int main(void)
{
int n;
scanf("%d", &n);
for (int i = 0; i < n; i++)
{
scanf("%d", &num[i]);
}
printf("%lld", merge_sort(0, n - 1));
return 0;
}