题目
归并排序的变种
刷题链接:https://www.acwing.com/problem/content/790/
分析
逆序对的解决方案当然可以一个元素和其他所有元素进行比较,但这样复杂度过高,会达到O(N2)
利用归并排序的复杂度,只需在其过程中添加一个计数操作即可
分为三种情况,其中黄色的情况(在两侧)是需要在归并的过程中处理的数据。两个数据q[i]和q[j]比较,如果发现前者大,那么(L,mid)区间内,q[i]及其后边的数据都比q[j]大,而且位置处于j的前边,都是逆序对。
一切都是因为给数据了一个规则,从无序的N2复杂度就变为了NlogN。这个题是给了一个有序的前提
这个题还有个数据范围的考虑,由于是100000的数据范围。因此考虑最坏的情况:数据逆序排列,n个数(n,n-1,n-2…2,1)–> 逆序对的数量就是(n-1)+(n-2)+…1 = n(n-1)/2
因此n2=1010/2 的范围,超过了int存储范围,因此采用long long 存储计算结果。
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 100010;
int q[N], tmp[N];
LL mergesort(int l, int r){
if(l>=r)return 0; //对于归并来说,这里可以写 == 号
int mid = l+r >> 1; //整除2
LL res = mergesort(l, mid) + mergesort(mid+1, r);
int i=l, j=mid+1, k=0;
while(i<=mid && j<=r){
if(q[i]>q[j]){
res += mid - i + 1;
tmp[k++] = q[j++];
}
else tmp[k++] = q[i++];
}
//扫尾
while(i<=mid)tmp[k++] = q[i++];
while(j<=r)tmp[k++] = q[j++];
//物归原主
for(int i=l, j=0; i<= r;i++,j++) q[i] = tmp[j];
return res;
}
int main(){
int n;
cin >> n;
for(int i=0;i<n;i++)cin >> q[i];
cout<<mergesort(0, n-1)<<endl;
return 0;
}