SCAU 數據結構 18746 逆序數

18746 逆序數

Description
在一個排列中,如果一對數的前後位置與大小順序相反,即前面的數大於後面的數,那麼它們就稱爲一個逆序。
一個排列中逆序的總數就稱爲這個排列的逆序數。逆序數是課程線性代數的一個知識點。
現在給定一個排列a1,a2,…,an,如果存在i<j並且ai>aj,那麼我們稱ai和aj爲一個逆序,請求出排列的逆序數。
輸入格式
第一行爲n,表示排列長度。(1=<n<=100000)
第二行有n個整數,依次爲排列中的a1,a2,…,an。所有整數均在int範圍內。
輸出格式
一個整數代表排列的逆序數。
輸入樣例
4
3 2 3 2
輸出樣例
3
提示
注意答案的數據範圍。

#include<iostream>
using namespace std;
int n,a[100005],temp[100005];//a是原數組,temp是臨時數組
long long sum=0;//注意逆序數數據範圍

void mergeSort(int left,int right) {//a、temp、sum都是全局變量可以不用傳
    if(right-left>1) {
        int mid = left+(right-left)/2;
        int temp_left=left,temp_right=mid,i=left;
        //temp_left和temp_right分別爲左右兩個待合併數組的遍歷腳標,i爲合併後數組的遍歷腳標
        //分治
        mergeSort(left,mid);
        mergeSort(mid,right);
        //歸併
        while(temp_left<mid || temp_right<right) {
            if(temp_right>=right||(temp_left<mid&&a[temp_left]<=a[temp_right])) {
                temp[i++]=a[temp_left++];//[]和後置++優先級都爲1,左結合
            } else {
                temp[i++]=a[temp_right++];
                sum += mid-temp_left;//在歸併排序的基礎上加上這一句
                //當右數組的元素要往前排的時候左數組中有mid-temp_left個數比他大,構成逆序
            }//明確"左右兩個數組分別都是有序的"就不難理解這一方法了
        }
        for(i=left; i<right; i++) {//從臨時數組複製回原數組
            a[i]=temp[i];
        }
    }
}

int main() {
    ios::sync_with_stdio(0),cin.tie(0);
    int i;
    cin>>n;
    for(i=0; i<n; i++) {
        cin>>a[i];
    }
    mergeSort(0,n);
    cout<<sum;
    return 0;
}
  • 根據題目給的範圍sum要用long long
  • 本題在歸併排序的基礎上加上這一句sum += mid-temp_left;即可
  • 時間複雜度爲O(nlogn) 需要額外大小爲n的空間
  • []和後置++優先級都爲1,左結合
  • 詳見註釋
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章