求排列的逆序數(分治)

2022-09-20 08:24:11 字數 1606 閱讀 8480

題目描述:考慮1,2,…,n (n <= 100000)的排列i1,i2,…,in,如果其中存在j,k,滿足 j < k 且 ij > ik, 那麼就稱(ij,ik)是這個排列的乙個逆序。

乙個排列含有逆序的個數稱為這個排列的逆序數。例如排列 263451 含有8個 逆序(2,1),(6,3),(6,4),(6,5),(6,1),(3,1),(4,1),(5,1),因此該排列的逆序數就是8。

現給定1,2,…,n的乙個排列,求它的逆序數。

其實笨辦法很簡單就是涉及乙個雙重迴圈。遍歷乙個數之後再往後遍歷找有沒有比這個數小的數,有的話就輸出相應的數。雙重迴圈很明顯複雜度是o(n^2)。

現在使用分治的思維,就是左邊來找逆序數,右邊再找逆序數,任何再找右邊乙個數左邊乙個數的逆序數(要求o(n)實現)。找左右兩邊都有的逆序數關鍵:

一開始讓i指向開頭的元素,讓j指向右半邊開頭的元素。將i與j比較,如果右半邊的數比左半邊大的話就把j往後移動知道j移到5停止。這樣後面的所有數就與10構成逆序數。任何i++就好了j也直接往後走。

/*

歸併排序是將兩個(或兩個以上)有序表合併成乙個新的有序表,即把待排序序列分為

* 若干個子串行,每個子串行是有序的,然後再把有序的子串行合併為整體有序序列

* 歸併排序是分治演算法的乙個典型的應用,而且是穩定的一種排序,這題利用歸併排序

* 的過程中,計算每個小區間的逆序數,進而得到大區間的逆序數。那麼,問題就解決了。

歸併排序是將數列a[l,h]分成兩半a[l,mid]和a[mid+1,h]分別進行歸併排序,然後再將這兩半合併起來。

在合併的過程中(設l<=i<=mid,mid+1<=j<=h),當a[i]<=a[j]時,並不產生逆序數;當a[i]>a[j]時,在

前半部分中比a[i]大的數都比a[j]大,將a[j]放在a[i]前面的話,逆序數要加上mid+1-i。因此,可以在歸併

排序中的合併過程中計算逆序數.

*/#include

#include

#include

using

namespace

std;

#define n 1000002

long

long

a[n],tmp[n];

long

long

ans;

//歸併排序的合併部分

void merge(int l,int m,int

r)

else

}while(i <= m) tmp[k++] = a[i++];

while(j <= r) tmp[k++] = a[j++];

for(int i=l;i<=r;i++)

a[i] =tmp[i];}//

l左端點,r右端點

//歸併排序

void merge_sort(int l,intr)}

intmain()

return0;

}

認真想一想,這個**和歸併排序的**的區別,就是在歸併排序的同時進行答案的計算,把兩邊按照從小到大來排序。

求排列的逆序數 分治

一 題目描述 總時間限制 1000ms 記憶體限制 65536kb 描述在internet上的搜尋引擎經常需要對資訊進行比較,比如可以通過某個人對一些事物的排名來估計他 或她 對各種不同資訊的興趣,從而實現個性化的服務。對於不同的排名結果可以用逆序來評價它們之間的差異。考慮1,2,n的排列i1,i2...

7622 求排列的逆序數 分治

描述 在internet上的搜尋引擎經常需要對資訊進行比較,比如可以通過某個人對一些事物的排名來估計他 或她 對各種不同資訊的興趣,從而實現個性化的服務。對於不同的排名結果可以用逆序來評價它們之間的差異。考慮1,2,n的排列i1,i2,in,如果其中存在j,k,滿足 j k 且 ij ik,那麼就稱...

求逆序數(分治法求解)

題目描述 在陣列中的兩個數字,如果前面乙個數字大於後面的數字,則這兩個數字組成乙個逆序對。輸入乙個陣列,求出這個陣列中的逆序對的總數p。並將p對1000000007取模的結果輸出。即輸出p 1000000007 輸入描述 題目保證輸入的陣列中沒有的相同的數字 資料範圍 對於 50的資料,size 1...