題目描述:考慮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...