求逆序對的兩種常用方法


  首先我們得理解一下什么是逆序對。在一個數列$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;
}

 

 

  


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM