归并排序求逆序对——归并排序思想的运用

题目:luogu1908.

题目大意:给定一串序列,求逆序对对数,其中逆序对定义为i<j且a[i]>a[j]的数对.

这道题很水,分治思想的简单应用.

首先我们可以想到归并排序(这里默认为从小到大排序),这个时候我们的归并排序需要一个返回值,表示在这个数列中的逆序对数量.

那么两段数列如何合并成一段数列呢?我们直接先把当前的答案先加上两段数列的答案和,然后在合并过程中,当前面一段数列[l,mid+1]中有数进来时,说明这个数只比它早进入数列的数大,也就是说它只能跟比它前面进入的数成逆序对,而跟它同样在前半段数列[l,mid+1]的数已经被统计过,所以只考虑后半段有多少数进入了,那么就是剩下的还要增加的数列.

然后合并的时候其实有一个细节,就是当a[i]=a[j]的时候,其中i是在前半部分的指针,j是在后半部分的指针,我们应该先加入a[i],原因是因为逆序对的定义是a[i]>a[j]而不是a[i]>=a[j].

代码如下:

#include<bits/stdc++.h>
  using namespace std;
#define Abigail inline void
typedef long long LL;
const int N=40000;
int a[N+1],r[N+1],n;
int mergesort(int L,int R){
  if (L==R) return 0;
  int mid=L+R>>1,sum=mergesort(L,mid)+mergesort(mid+1,R),i=L,j=mid+1,k=L;
  while (i<=mid&&j<=R)
    if (a[i]<=a[j]) sum+=j-mid-1,r[k++]=a[i++];
    else r[k++]=a[j++];
  while (i<=mid) sum+=j-mid-1,r[k++]=a[i++];
  while (j<=R) r[k++]=a[j++];
  for (int t=L;t<=R;t++) a[t]=r[t];
  return sum;
}
Abigail into(){
  scanf("%d",&n);
  for (int i=1;i<=n;i++)
    scanf("%d",&a[i]);
}
Abigail work(){
}
Abigail outo(){
  printf("%d\n",mergesort(1,n));
}
int main(){
  into();
  work();
  outo();
  return 0;
}

猜你喜欢

转载自blog.csdn.net/hzk_cpp/article/details/81050230