现在给定一个有 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
通过归并排序实现。
#include <stdio.h>
int arrTmp[100010]; //定义一个临时数组
//归并两个分段的结果,两个分段是数组中的[low,mid]以及[mid+1,high]中的元素
long long num;
void Merge(int arr[],int low,int mid,int high){
int i=low,j=mid+1,k=low; //I、J、K分别指向待归并的两段以及临时数组
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[N];
for(int j=0;j<N;j++){
scanf("%d",&arr[j]);
}
MergeSort(arr,0,N-1);
printf("%lld\n",num);
}
}
}