在一个排列中,如果一对数的前后位置与大小顺序相反,即前面的数大于后面的数,那么它们就称为一个逆序。一个排列中逆序的总数就称为这个排列的逆序数。
如2 4 3 1中,2 1,4 3,4 1,3 1是逆序,逆序数是4。给出一个整数序列,求该序列的逆序数。
Input
第1行:N,N为序列的长度(n <= 50000) 第2 - N + 1行:序列中的元素(0 <= A[i] <= 10^9)
Output
输出逆序数
Input示例
4 2 4 3 1
Output示例
4
方法1:归并排序
#include<stdio.h>
#define maxsize 50010
long long int count = 0;
int a[maxsize],temp[maxsize];
void merge(int s,int m,int e)
{
int p1 = s,p2 = m+1,p = 0;
while(p1 <= m && p2 <= e)
{
if(a[p1]<=a[p2])
temp[p++]=a[p1++];
else
{
temp[p++]=a[p2++];
count += m-p1+1;
}
}
while(p1<=m)
temp[p++]=a[p1++];
while(p2<=e)
temp[p++]=a[p2++];
int i;
for(i = 0;i < p; ++i)
a[s+i] = temp[i];
}
void mergesort(int l,int r)
{
if(l<r)
{
int m = (l+r)/2;
mergesort(l,m);
mergesort(m+1,r);
merge(l,m,r);
}
}
int main()
{
int n,i;
scanf("%d",&n);
for(i=0;i<n;i++)
scanf("%d",&a[i]);
mergesort(0,n-1);
printf("%lld\n",count);
return 0;
}
方法二:树状数组 + 离散化
离散化参考:
离散化
树状数组:
树状数组讲解
树状数组求逆序原理:点击打开链接
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50005;
int C[MAXN];
int a[MAXN];
int n;
struct Node{
int d,ord;//数据与 位置
bool operator<(const Node o)const{
return d < o.d;
}
}p[MAXN];
int lowBit(int i){
return i&(-i);
}
int add(int i,int x){
while(i <= n){
C[i] += x;
i += lowBit(i);
}
}
int getSum(int i){
int sum = 0;
while(i){
sum += C[i];
i -= lowBit(i);
}
return sum;
}
int main()
{
scanf("%d",&n);
memset(C,0,sizeof(C));
for(int i = 1; i <= n; ++i){//从1开始
scanf("%d",&p[i].d);
p[i].ord = i;
}
sort(p+1,p+n+1);//按照数据大小 从小到大排序
//数据被离散化为从1开始的数
for(int i = 1; i <= n; ++i){
a[p[i].ord] = i;
}
int ans = 0;
for(int i = 1; i <= n; ++i){
add(a[i],1);//a[i]表示新的数据
ans += i - getSum(a[i]); //这里 i可以用getSum(n)代替 i表示当前共有多少数 减去比a[i]小的数
}
printf("%d\n",ans);
return 0;
}
在数据范围比较小的情况下,可以不用离散化
但是需要注意,数据不能有 0 值,若有0可以对每个数据加一的方式或者进行离散化
原因:0&0 == 0 此时无法实现i的更新 会进入死循环(add中的while)
#include<bits/stdc++.h>
using namespace std;
const int MAXN = 50000;
int C[MAXN];
int n;
int lowBit(int i){
return i&(-i);
}
int add(int i, int x){
while(i <= n){
C[i] += x;
i += lowBit(i);
}
}
int getSum(int i){
int sum = 0;
while(i > 0){
sum += C[i];
i -= lowBit(i);
}
return sum;
}
int main()
{
memset(C,0,sizeof(C));
scanf("%d",&n);
int x;
int ans = 0;
for(int i = 1; i <= n; ++i){
scanf("%d",&x);
add(x,1);
ans += i - getSum(x);
}
printf("%d\n",ans);
// for(int i = 1; i <= n; ++i){
// printf("%d ",C[i]);
// }
//cout << getSum(5)-getSum(3);
return 0;
}