逆序對:對於數列的第 \(i\) 個和第 \(j\) 個元素,如果滿足 \(i < j\) 且 \(a[i] > a[j]\),則其為乙個逆序對。
暴力求法就是兩遍for迴圈,\(o(n^2)\)超時
用歸併可以順便求出來,\(o(nlogn)\)
在一次歸併排序中,因為歸併要求將乙個完整區間分為兩塊,所以逆序對出現了三種情況。
逆序對在mid的左邊
逆序對在mid的右邊
逆序對的兩個元素乙個在mid左邊,乙個在mid右邊
之前提過歸併可以順便求出來,這裡設歸併排序有大小為該區間逆序對個數的返回值,即\(l-r的逆序對個數=merge\_sort(l,r)\)
因為是遞迴處理嘛,所以先將左右兩邊的歸併排序。重點是第三部分,如何處理這種情況。
首先,通過前兩次歸併排序,從\(l-mid,mid+1-r\)兩個部分都是有序的,在合併這兩個有序序列時,可以求出第三種情況的逆序對個數。
重新想一下逆序對的定義,是在前面的數比後面的數大。在區間上來看,就是\(l-mid\)的這一部分中有元素比\(mid+1-r\)中的元素大。
每次移動右半邊的指標時,從中間到左半邊指標所包含的所有數字 都是大於右半邊指標所指向的數字的,這些都可以組成逆序對,直接加上即可。
最後呢,其實1和2的情況沒有討論,因為歸併排序最後還是要分到只有兩個數進行排序的。乙個數不能構成逆序對,所以只有兩個數字的情況下,只存在第三種情況,接著往下遞迴就不需要考慮12了。
**:
#include using namespace std;
typedef long long ll;
typedef unsigned long long ull;
const int maxn = 1e5 + 10;
int n, q[maxn], tmp[maxn];
ll solve(int l, int r)
}while (i <= mid)
tmp[k++] = q[i++];
while (j <= r)
tmp[k++] = q[j++];
for (int i = l; i <= r; i++)
q[i] = tmp[i];
return ans;
}int main()
歸併排序求逆序對
排序都用qsort了,別的排序演算法不怎麼用,但有些排序的思想很重要。碰到一道求逆序對的題,要用到歸併排序,學習了一下歸併排序。歸併排序是用分治思想,分治模式在每一層遞迴上有三個步驟 分解 將n個元素分成個含n 2個元素的子串行。解決 用合併排序法對兩個子串行遞迴的排序。合併 合併兩個已排序的子串行...
歸併排序求逆序對
我們知道,求逆序對最典型的方法就是樹狀陣列,但是還有一種方法就是merge sort 即歸併排序。實際上歸併排序的交換次數就是這個陣列的逆序對個數,為什麼呢?我們可以這樣考慮 歸併排序是將數列a l,h 分成兩半a l,mid 和a mid 1,h 分別進行歸併排序,然後再將這兩半合併起來。在合併的...
歸併排序求逆序對
現在給定乙個有n個數的數列ai。若對於i j,有ai aj,則稱 i,j 為數列的乙個逆序對。例如,2,3,8,6,1 有五個逆序對,分別是 1,5 2,5 3,4 3,5 4,5 現在請你求出乙個給定數列的逆序對個數。輸入格式 乙個整數t,表示有多少組測試資料。每組測試資料第一行是乙個正整數n 1...