求逆序对
问题:
问题描述:
猫猫 TOM 和小老鼠 JERRY 最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。
最近,TOM 老猫查阅到一个人类称之为 “逆序对” 的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中 ai>aj
且 i<j 的有序对。知道这概念后,他们就比赛谁先算出给定的一段正整数序列中逆序对的数目。注意序列中可能有重复数字。
输入格式:
第一行,一个数 nn,表示序列中有 nn 个数。 第二行 nn 个数,表示给定的序列。序列中每个数字不超10^9。
输出格式:
输出序列中逆序对的数目。
输入样例:
6
5 4 2 6 3 1
输出样例:
11
说明/提示:
对于所有数据,n <= 5* 10^5
思考:
求解思路是递归,分而治之,利用了归并排序。在进行二路归并的时候对逆序对进行统计。
如图所示:

在每一次递归排序的时候统计逆序对的数量。
代码:
divide()函数的目的在于把序列划分,然后调用sort()函数进行排序。
#include <iostream>
using namespace std;
long long s = 0;
void divide(int *a, int left, int right);
void merge(int *a, int b1, int e1, int b2, int e2); //归并排序
int main()
{
int n;
cin >> n;
int a[500010];
for (int i = 1; i <= n; i++)
cin >> a[i];
divide(a, 1, n);
cout << s << endl;
}
void divide(int *a, int left, int right)
{
int mid = (left + right) / 2;
if (left >= right)
{
// do nothing
}
else
{
divide(a, left, mid);
divide(a, mid + 1, right);
merge(a, left, mid, mid + 1, right);
}
}
void merge(int *a, int b1, int e1, int b2, int e2)
{
int i, j, k;
i = b2, j = b1, k = 0;
long long temp[e2 - b1 + 2]; //辅助数组
while (i <= e2 && j <= e1) //归并排序
{
if (a[i] < a[j])
{
s += (e1 - j + 1);
temp[k] = a[i];
i++;
}
else
{
temp[k] = a[j];
j++;
}
k++;
}
if (i <= e2)
for (; i <= e2; i++, k++)
temp[k] = a[i];
if (j <= e2)
for (; j <= e1; j++, k++)
temp[k] = a[j];
k--;
// 把排序后的数据在复制回a数组中
for (i = b1, j = 0; j <= k && i <= e2; j++, i++)
a[i] = temp[j];
}

浙公网安备 33010602011771号