逆序對問題

逆序對是什麼,對於一個序列a1,a2,a3.....an來說,,,滿足a[ i ]>a[ j ]並且i < j的數對(i,j)就叫做逆序對。

一些性質:

1.對於一個逆序對爲k的序列來說,要將這個序列排序成爲完全沒有逆序對的序列,即任意兩個元素之間都滿足比較關係,則至少需要交換相鄰序對的次數爲序列的逆序對數k,並且一定存在一個k次交換相鄰元素的算法。

2.對於一個元素全部相同的序列來說,選擇其中的一個逆序對進行交換,總的逆序對個數變化將會減少奇數次。因爲我們可以任選一個序列中的逆序對。 .........ai.....aj......  對於ai 和 aj 分別左邊和右邊的數來說,他們對整個逆序對的貢獻將會不變。只用考慮在ai和aj中間的數,分爲三類,完全大於max(ai,aj)x個 、完全小於min(ai,aj)y個、處於ai,aj之間的數z個。中間的數貢獻會減少2z個貢獻(分析一下就知道),加上ai,aj本身減少了1個貢獻,總的逆序對數會減少1+2z個。

3.對於一串0-n的數字組組成的序列,最前面的數字 a[0]的貢獻是a[n],最後面一個數字a[n]的貢獻是n-a[n].

算法實現:

歸併排序:


int n;
int a[maxn];
int temp[maxn];
ll ans;
void msort(int l,int r,int *a,int *temp)    //mergrsort();
{
    if(l==r)
        return;

    int mid=(l+r)/2;
    msort(l,mid,a,temp);
    msort(mid+1,r,a,temp);

    int i=l,j=mid+1;     //指向a左邊和右邊的指針
    int k=l;             //指向temp位置的指針
    while(i<=mid&&j<=r)  //兩兩比較,知道其中一個到達末端
    {
        if(a[i]<=a[j])
            temp[k++]=a[i++];
        else
        {
            temp[k++]=a[j++];
            ans=ans+(mid-i+1);
        }
    }

    while(i<=mid)          //將剩下的放入temp中
        temp[k++]=a[i++];
    while(j<=r)
        temp[k++]=a[j++];

    for(i=l; i<=r; i++)   //temp反複製進入a
        a[i]=temp[i];
}
//調用
ll getMergeSort(int l,int r,int *a)
{
    ans=0;
    msort(l,r,a,temp);

    return ans;
}



 

線段樹:

 

八數碼等方格移動問題

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章