求逆序對

逆序對的定義:html

在一個數列aa中,知足a[i]>a[j]a[i]>a[j]而且i<ji<j的數對就叫作逆序對。數組

解法:ide

通常有兩種解法:歸併排序和樹狀數組函數

歸併排序動圖:atom

 

 

歸併求逆序對:spa

歸併排序用到了二分的思想,在排序過程當中若是a[i]<=a[j就不會產生逆序對,若是a[i]>a[j]就會產生midi+1個逆序對,3d

由於作歸排的時候lmidmid+1~r都是已經排好序的因此若是a[i]>a[j]那麼a[i+1]a[mid]也就都大於a[j]。
code

#include<cstdio>
#include<algorithm>
#define maxn 1000
using namespace std;
int n,A[maxn],temp[maxn],ans;
void merge(int L1,int R1,int L2,int R2)
{
    int k=0,i=L1,j=L2;
    while(i<=R1 && j<=R2)
    {
        if(A[i]<=A[j]) temp[k++]=A[i++];
        else if(A[i]>A[j])
        {
            ans+=(R1-i+1);
            temp[k++]=A[j++];
        }
    }
    while(i<=R1) temp[k++]=A[i++];
    while(j<=R2) temp[k++]=A[j++];
    for(i=0;i<k;i++) A[L1+i]=temp[i];
}
void mergeSort(int L,int R)
{
    if(L<R)
    {
        int mid = (L+R)/2;
        mergeSort(L,mid);
        mergeSort(mid+1,R);
        merge(L,mid,mid+1,R);
    }
}
int main(void)
{
    scanf("%d",&n);
    for(int i=0;i<n;i++) scanf("%d",&A[i]);
    mergeSort(0,n-1);
    printf("%d",ans);
    return 0;
}
View Code

 

樹狀數組:xml

1.可以查詢某段區間的和;2.可以隨時更新某個數的值。htm

使用函數int sum(int k)計算a[1]+a[2]+...+a[k]的值。

使用函數update(int k,int change)更新全部包含a[x]的t[i],讓t[i]+=change;

使用樹狀數組求逆序對可能還須要進行離散化操做(由於數據過大的話沒法直接開數組),

對於離散後的序列進行一次遍歷,遍歷過程當中就向樹狀數組C進行插入操做(每次插入的值爲1),

這裏樹狀數組表示的是在該元素前面可是比該元素大的元素個數,進行插入操做之後就查詢。

#include<cstdio>
#define maxn 100010
int n,a[maxn],t[maxn],ans;
int sum(int k)
{
    int s = 0;
    for(int i=k;i>0;i-=i&(-i)) s+=t[i];//所求的區間長度和 = 當前管線的區間和 + 剩下的區間長度和
    return s;
}
void update(int k,int change)
{
    for(int i=k;i<=n;i+=i&(-i)) t[i]+=change;//每一次循環就是找到了下一個包含k的區間對應的t[i]
}
int main(void)
{
    int num;
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    {
        scanf("%d",&num);
        a[num]++;
        update(num,1);
        ans+=i-sum(num);//sum(num)計算的是小於等於num的總數,當前總數i-sum(num)大於num的元素的個數,就是逆序的個數。
    } 
    printf("%d",ans);
    return 0;
}
View Code
相關文章
相關標籤/搜索