题目:
现在给定一个有 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
注意:
本题如果用普通的双重循环遍历求解问题,时间复杂度为O(n^2)会导致超时;
采用归并排序,时间复杂度为O(nlogn)不会超时;
有一个小陷阱,就是逆序对的个数可能会超过int的范围,因为若整数序列是从100,000,000递减,那么逆序对的个数就会是
100,000,000*(100,000,000+1)/2, 所以需要将其设置为long long 类型。
下面是本人的代码:
#include<stdio.h> #include<malloc.h> #define MAX 100000 int N; long long count; int a[MAX]; void print(int a[]) { int i; for(i=0;i<N;i++) printf("%d ",a[i]); printf("\n"); } void merge(int a[], int low,int mid, int high) { //printf("对下标%d--%d排序\n",low,high); int* temp=(int*)malloc(sizeof(int)*(high-low+1)); int i=low, j=mid+1,ti=0; while(i<=mid && j<=high) { if(a[i]<=a[j]) temp[ti++]=a[i++]; else { temp[ti++]=a[j++]; count=count+(mid-i+1); //关键:如果a[i]>a[j], 那么a[i]到a[mid]都大于a[j], 逆序对个数增加mid-i+1个 } } while(i<=mid) { temp[ti++]=a[i++]; count+=high-j+1; } while(j<=high) temp[ti++]=a[j++]; for(i=0;i<ti;i++) a[low+i]=temp[i]; //print(a); } void mergeSort(int a[], int low,int high) { if(low<high) { int mid=(low+high)/2; mergeSort(a,low,mid); mergeSort(a,mid+1,high); merge(a,low,mid,high); } } void testTwo() { int i, j; scanf("%d",&N); for(i=0;i<N;i++) scanf("%d",&a[i]); mergeSort(a,0,N-1); //printf("排序结果:\n"); //for(i=0;i<N;i++) //printf("%d ",a[i]); printf("%lld\n",count); }; int main() { int T; scanf("%d",&T); while(T--) { count=0; testTwo(); } }
#include <bits/stdc++.h> using namespace std; const int N = 1e5+5; typedef long long LL; int n, a[N], b[N]; LL merge_sort(int l, int r) { if (l + 1 == r) return 0; int m = (l + r) / 2; LL ret = merge_sort(l, m) + merge_sort(m, r); for (int i = l, j = m, k = l; k < r; ++k) if (i == m) b[k] = a[j++]; else if (j == r) b[k] = a[i++]; else if (a[i] <= a[j]) b[k] = a[i++]; else b[k] = a[j++], ret += m - i; for (int i = l; i < r; ++i) a[i] = b[i]; return ret; } int main() { int T; cin >> T; while (T--) { cin >> n; for (int i = 0; i < n; ++i) cin >> a[i]; LL ans = merge_sort(0, n); cout << ans << endl; } }