二分 歸併排序之逆序對 演算法講解和題目

2022-08-31 15:36:15 字數 1708 閱讀 3333

題目:

時間限制:10000ms

單點時限:1000ms

記憶體限制:256mb

描述在上一回、上上回以及上上上回里我們知道nettle在玩《艦これ》。經過了一番苦戰之後,nettle又獲得了的很多很多的船。

這一天nettle在檢查自己的艦隊列表:

我們可以看到,船預設排序是以等級為引數。但實際上乙個船的火力值和等級的關係並不大,所以會存在a船比b船等級高,但是a船火力卻低於b船這樣的情況。比如上圖中77級的飛龍改二火力就小於55級的夕立改二。

現在nettle將按照等級高低的順序給出所有船的火力值,請你計算出一共有多少對船滿足上面提到的這種情況。

輸入第1行:1個整數n。n表示艦船數量, 1≤n≤100,000

第2行:n個整數,第i個數表示等級第i低的船的火力值a[i],1≤a[i]≤2^31-1。

輸出第1行:乙個整數,表示有多少對船滿足「a船比b船等級高,但是a船火力低於b船」。

樣例輸入

10

1559614248 709366232 500801802 128741032 1669935692 1993231896 369000208 381379206 962247088 237855491

樣例輸出

27
解題思路:

那麼這個題,我們沒有用最開始的bit去做,我是借鑑了acdreamer的部落格,然後使用歸併排序來解決這個問題。實際上,歸併排序過程中,交換的次數其實就是這個陣列中逆序對的個數。我們可以這樣考慮,

有乙個陣列a[lo...hi],那麼歸併排序實際上就是將陣列分成a[lo...mid]和a[mid+1...hi]這樣的形式,然後分別歸併排序,最後再將其合併起來的過程。在合併的過程中(lo<=i<=mid, mid+1<=j<=hi),當a[i]<=a[j]的時候,這個時候的並不會產生逆序數。當a[i]>a[j]的時候,這個時候就會產生逆序數了。因為在a[i]後面比a[i]大的數字都會比a[j]大,並且假設這個時候merge_sort(lo,mid)已經是乙個有序的部分了。那麼現在將a[j]放到a[i]的前面的話,逆序數就好增加ans+=mid+1-i個。因此我們可以邊歸併,邊計算。

**:

1 # include 2 # include 3

using

namespace

std;

4 # define max 123456

5int

a[max],res[max];

6long

long ans = 0;7

void merge( int lo,int mid,int

hi )820

else

2124}25

while ( i <=mid )

2629

while ( j <=hi )

3033

for ( int i = lo;i <= hi;i++)

3437}38

void merge_sort( int lo,int

hi )

3947}48

int main(void)49

55 merge_sort(0,n-1

);56 cout

57return0;

58 }

二分歸併排序演算法 排序演算法之歸併排序

一 分治模式 許多有用的演算法在結構上是遞迴的 為了解決乙個給定的問題,演算法一次或多次遞迴地呼叫其自身以解決緊密相關的若干子問題。這些演算法典型地遵循分治法的思想 將原問題分解為幾個規模較小但類似於原問題的子問題。遞迴的求解這些問題,然後再合併這些子問題的解來建立原問題的解。分治模式在每層遞迴都有...

二分歸併排序 分治演算法與歸併排序

距離上次寫快排演算法的文章已經過去乙個半月了,和本文要提到的歸併排序演算法類似,快排也是分治思想的一種典型應用,如果有不熟悉快速排序的同學可以翻閱我之前寫過的的快速排序演算法的文章。首先為大家介紹一下什麼是分治,分治是將乙個大問題分割成若干個和原來問題形式相同但規模更小的子問題,然後處理這些小問題,...

歸併排序 二分

歸併排序就是將陣列反覆拆分成兩部分,然後分別在這兩部分裡面再反覆拆分,講拆分成的兩部分按順序排好之後再歸併起來,歸併起來之後再反覆交換位置,最終使整個陣列按順序排列。具體操作方法 按從小到大排 拆分成的兩部分依次比較,若前半部分的較小,將其存入陣列tmp中,將前面的下標i 若後面一部分較小,則將後面...