题目描述
猫猫TOM和小老鼠JERRY最近又较量上了,但是毕竟都是成年人,他们已经不喜欢再玩那种你追我赶的游戏,现在他们喜欢玩统计。最近,TOM老猫查阅到一个人类称之为“逆序对”的东西,这东西是这样定义的:对于给定的一段正整数序列,逆序对就是序列中ai>aj且i
解题思路
有两种解法,第一种是树状数组,首先先按照数字排序,之后进行对下标的单点修改和区间查询。第二种是归并排序,每次合并时ans+=mid-i+1;复杂度都是O(nlogn)
代码
1、树状数组
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstdlib>
using namespace std;
const int MAXN = 40005;
int n,f[MAXN],ans;
struct DATA{
int a,id;
}t[MAXN];
inline bool cmp(DATA A,DATA B){
return A.a>B.a;
}
inline void add(int x,int y){
for(;x<=n;x+=x&-x)
f[x]+=y;
}
inline int query(int x){
int ret=0;
for(;x;x-=x&-x)
ret+=f[x];
return ret;
}
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++){
scanf("%d",&t[i].a);
t[i].id=i;
}
sort(t+1,t+1+n,cmp);
for(register int i=1;i<=n;i++){
add(t[i].id,1);
ans+=query(t[i].id-1);
}
printf("%d",ans);
return 0;
}
2、归并排序
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
const int MAXN = 40005;
int n,a[MAXN],cpy[MAXN];
int ans;
inline void merge_sort(int l,int r){
if(l==r) return;
int mid=l+r>>1;
merge_sort(l,mid);
merge_sort(mid+1,r);
int i=l,j=mid+1,k=l;
while(i<=mid && j<=r){
if(a[i]>a[j]){
ans+=mid-i+1;
cpy[k++]=a[j++];
}
else cpy[k++]=a[i++];
}
while(i<=mid) cpy[k++]=a[i++];
while(j<=r) cpy[k++]=a[j++];
for(register int i=l;i<=r;i++) a[i]=cpy[i];
}
int main(){
scanf("%d",&n);
for(register int i=1;i<=n;i++) scanf("%d",&a[i]);
merge_sort(1,n);
printf("%d",ans);
return 0;
}