Time Limit: 2 Seconds Memory Limit: 65536 KB
现在给定一个有 N 个数的数列 Ai。若对于 i < j,有 Ai > Aj,则称 (i, j) 为数列的一个逆序对。
例如,<2, 3, 8, 6, 1> 有五个逆序对,分别是 (1, 5), (2, 5), (3, 4), (3, 5), (4, 5)。
现在请你求出一个给定数列的逆序对个数。
提示:排序算法可以解决这个问题。
输入格式
一个整数 T,表示有多少组测试数据。
每组测试数据第一行是一个正整数 N (1 <= N <= 100000),表示数列中有 N 个数字。
接下来一行包含 N 个正整数,代表对应的数列。
保证所有正整数小于 100000000。
输出格式
对于每组数据,输出一行,表示逆序对的个数。
样例输入
1
5
2 3 8 6 1
样例输出
5
思路: 归并排序求逆序数。合并排序在合并阶段分为两个序列(设L[]与R[]),L序列与R序列分别是经过排序的。每次从两个序列中取值时分两种情况:(1)从L中取值,这样取出的值的逆序数为0;(2)从R中取值,这时,取出的值的逆序数为L中剩余元素的个数。
#include <stdio.h>
int arrTmp[100010];
long long num;
void Merge(int arr[], int low, int mid, int high){
int i = low, j = mid + 1, k = low;
while (i <= mid&&j <= high){
if (arr[i] <= arr[j]){
arrTmp[k++] = arr[i++];
}
else{
arrTmp[k++] = arr[j++];
num += mid - i + 1;
}
}
while (i <= mid){
arrTmp[k++] = arr[i++];
}
while (j <= high){
arrTmp[k++] = arr[j++];
}
for (i = low; i <= high; i++){
arr[i] = arrTmp[i];
}
}
void MergeSort(int arr[], int low, int high){
if (low<high){
int mid = (low + high) / 2;
MergeSort(arr, low, mid);
MergeSort(arr, mid + 1, high);
Merge(arr, low, mid, high);
}
}
int main(){
int T;
while (scanf("%d", &T) != EOF){
for (int i = 0; i<T; i++){
int N;
num = 0;
scanf("%d", &N);
int arr[100000];
for (int j = 0; j<N; j++){
scanf("%d", &arr[j]);
}
MergeSort(arr, 0, N - 1);
printf("%lld\n", num);
}
}
}