Evanyou Blog 彩带

求逆序对的两种常用方法

  首先我们得理解一下什么是逆序对。在一个数列$a$中,满足$a[i]>a[j]$并且$i<j$的数对就叫做逆序对。

  一般求逆序对常用的有两种方法,归并排序和树状数组。(我个人比较喜欢归排)这两样不会的请出门左转百度。

  下面就讲讲这两种方法:

  首先讲讲归排求逆序对。归并排序用到了二分的思想,在排序过程中如果$a[i]<=a[j]$就不会产生逆序对,如果$a[i]>a[j]$就会产生$mid-i+1$个逆序对,因为做归排的时候$l~mid$和$mid+1~r$都是已经排好序的所以如果$a[i]>a[j]$那么$a[i+1]~a[mid]$也就都大于$a[j]$,这个非常容易懂,下面是代码:

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=40005;
int n,a[N],c[N],ans;
void ready()
{
  cin>>n;
  for(int i=1;i<=n;i++)
    cin>>a[i];
}
inline void msort(int l,int r)
{
  if(l==r)return;
  int mid=(l+r)>>1;
  msort(l,mid);msort(mid+1,r);
  int i=l,j=mid+1,k=l;
  while(i<=mid&&j<=r){
    if(a[i]<=a[j])
      c[k++]=a[i++];
    else{
      c[k++]=a[j++];
      ans+=(mid-i+1);
    }
  }
  while(i<=mid)c[k++]=a[i++];
  while(j<=r)c[k++]=a[j++];
  for(i=l;i<=r;i++)
    a[i]=c[i];
}
void work()
{
  msort(1,n);
  cout<<ans<<endl;
}
int main()
{
  std::ios::sync_with_stdio(false);
  ready();work();return 0;
}

 

  再来讲讲树状数组,这个可能比归排的要不那么容易理解。使用树状数组求逆序对还需要进行离散化操作(因为数据过大的话无法直接开数组),对于离散后的序列进行一次遍历,遍历过程中就向树状数组C进行插入操作(每次插入的值为1),这里树状数组表示的是在该元素前面但是比该元素大的元素个数,进行插入操作以后就查询。。。我觉得看代码貌似会容易理解一点。。

#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<cmath>
#include<algorithm>
#include<iostream>
using namespace std;
const int N=40005;
int n,b[N],c[N],ans;
struct node{int v,id;}a[N];
inline int lowbit(int x)
{return x&(-x);}
inline void insert(int i,int x)
{
  while(i<=n){
    c[i]+=x;i+=lowbit(i);
  }
}
inline int getnum(int x)
{
  int ret=0,i=x;
  while(i>0){
    ret+=c[i];i-=lowbit(i);
  }
  return ret;
}
inline bool cmp(node x,node y)
{return x.v<y.v;}
void work()
{
  cin>>n;
  for(int i=1;i<=n;i++){
    cin>>a[i].v;
    a[i].id=i;
  }
  sort(a+1,a+n+1,cmp);
  for(int i=1;i<=n;i++)b[a[i].id]=i;
  for(int i=1;i<=n;i++){
    insert(b[i],1);
    ans+=i-getnum(b[i]);
  }
  cout<<ans<<endl;
}
int main()
{
  std::ios::sync_with_stdio(false);
  work();return 0;
}

 

 

  

posted @ 2017-11-10 09:09  HolseLee  阅读(9778)  评论(2编辑  收藏  举报