对于给定的序列A={a0,a1,…,an−1},若二元组(i,j)满足ai>aj,i<j则称(i,j)为一个逆序。给定序列中逆序的数量称为该序列的逆序数。 可以证明,逆序数等于以下程序中定义的冒泡排序的交换次数:
bubbleSort(A)
cnt = 0 // the number of inversions
for i = 0 to A.length-1
for j = A.length-1 downto i+1
if A[j] < A[j-1]
swap(A[j], A[j-1])
cnt++
return cnt
对于给定的序列A,打印A的逆序数。注意不要使用上面的程序,这会导致程序运行超时。
输入
在第一行中,给出了一个整数 n,即 A 中元素的数量。
在第二行中,元素ai(i=0,1,…,n−1)由空格字符分隔。
输出
打印逆序数。
约束
1≤n≤200,000
0≤ai≤10^9
ai都不同
输入样例
5
3 5 2 1 4
输出样例
6
题目中给出提示,在排序中计算逆序数
由于冒泡排序的时间复杂度是O(n^2),所以我们要选择更好的排序方法
我们选择归并排序O(nlogn),直接把上一道题中的代码拿过来用就行
c变为逆序数,当我们选择右侧R[j]并放入合并后的数组时,左侧L[]中剩下的所有元素都大于R[j]
所以,c+=(n1-i)
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
long long c=0;
void Merge(int * a,int left,int mid,int right)
{
int n1=mid-left;
int n2=right-mid;
int *L=(int*)malloc((n1+1)*sizeof(int));
int *R=(int*)malloc((n2+1)*sizeof(int));
for(int i=0;i<n1;i++)
{
L[i]=a[left+i];
}
for(int i=0;i<n2;i++)
{
R[i]=a[mid+i];
}
L[n1]=__INT_MAX__;
R[n2]=__INT_MAX__;
int i=0,j=0;
for(int k=left;k<right;k++)
{
if(L[i]<=R[j])
{
a[k]=L[i];
i++;
}
else
{
a[k]=R[j];
c+=(n1-i);
j++;
}
}
free(L);
free(R);
}
void MergeSort(int * a,int left,int right)
{
if(left+1<right)
{
int mid=(left+right)/2;
MergeSort(a,left,mid);
MergeSort(a,mid,right);
Merge(a,left,mid,right);
}
}
int main()
{
int n;
scanf("%d",&n);
int *a=(int *)malloc(n*sizeof(int));
for(int i=0;i<n;i++)
{
scanf("%d",&a[i]);
}
MergeSort(a,0,n);
printf("\n%lld",c);
free(a);
return 0;
}