题目大意:
现有一个n长的无序数列,并且定义:若i<j,a[i]>a[j],则称无序对<a[i],a[j]>是逆序对。现求数列中是有多少逆序对。
题目解析:
大致思路:
利用归并排序的思想,将其分为若干个小区间(长度为1),每两个区间内前后对比判断逆序对(1、2为一组,3、4为一组......以此类推),然后进行排序合并,这样每个合并后的区间内虽然顺序改变过但在改变之前就已经进行过统计,并且顺序的改变只是在合并后的区间内,区间之间并没有进行过改变,所以仍可以利用以上步骤进行统计。
踩过的坑:
因为每个长度大于等于2的区间都是排过序逇小区间,所以在找到一个满足的后,a[i]到a[mid]都是满足的,所以直接cnt+=mid-i+1。
还有就是统计出来的个数会爆int,所以得用long long。
AC代码:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#define ll long long
#define in(x) scanf("%d",&x)
#define in64(x) scanf("%lld",&x)
#define debug(x) cerr<<#x<<" : "<<x<<endl
using namespace std;
const int maxn = 100005;
int a[maxn],tmp[maxn];
ll merge(int l,int r){
ll cnt = 0;
if(l >= r){
return cnt;
}
int mid = l + r >> 1;
cnt += merge(l,mid);
cnt += merge(mid+1,r);
int k = 1;
int i = l,j = mid + 1;
while(i <= mid&&j <= r){
if(a[i] <= a[j]){
tmp[k++] = a[i++];
}
else{
tmp[k++] = a[j++];
cnt += mid - i + 1;
}
}
while(i <= mid) tmp[k++] = a[i++];
while(j<=r) tmp[k++] = a[j++];
for(i = l , j = 1 ; i <= r ; i++ , j++ ){
a[i] = tmp[j];
}
return cnt;
}
int main(){
int n;in(n);
for(int i = 1 ; i <= n ; i++ ) {
in(a[i]);
}
ll res = merge(1,n);
cout<<res<<endl;
return 0;
}