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