acwing 788.逆序對的數量
看了大佬的題解後對於歸併又有了更深的理解,在這裡引用一下dongwa_zzuli大佬的題解acwing 788. 逆序對的數量,感興趣的小夥伴可以看看給定乙個長度為n的整數數列,請你計算數列中的逆序對的數量。
逆序對的定義如下:對於數列的第 i 個和第 j 個元素,如果滿足 i < j 且 a[i] > a[j],則其為乙個逆序對;否則不是。
輸入格式
第一行包含整數n,表示數列的長度。
第二行包含 n 個整數,表示整個數列。
輸出格式
輸出乙個整數,表示逆序對的個數。
資料範圍
1 ≤n
≤100000
1≤n≤100000
1≤n≤10
0000
輸入樣例:
6
2 3 4 5 6 1
輸出樣例:5
(歸併排序) o(n
logn
)o(nlogn)
o(nlog
n)做這道題的話因為序列是不能被打亂的,而歸併排序開始排序之前,序列還是原來的樣子。根據這道題的性質我們可以發現,一共有三種情況,也就是這兩個數的位置。
剛好在左區間前兩個情況很好求,在我們處理左右區間時就可以求出來,那麼第三種呢。其實也不難,根據歸併的性質可以知道在歸併到最後乙個區間的時候左右兩個子區間是有序的,那麼我們歸併的時候可以判斷一下,如果左指標所指的數大於右指標所指的數,那麼左指標後的所有數都將大於它,那麼這個數構成的逆序對就是剛好在右區間
大的數在左區間,小的數在右區間
mid - i + 1
,那麼只需將所有這種情況加起來,再加上前兩種情況就行了。前兩種情況其實在合併為將它們分開時的那個區間時就已經計算完了,只需把merge_sort(q , l , mid)
和merge_sort(q , mid + 1 , r)
這兩個結果加起來就行了,雖然看上去有點繞,但是如果你知道歸併的過程的話,其實就能明白了,還是不太清楚的話建議手動模擬一下,也可以看看我畫的圖
其實這裡還有乙個很小的細節,因為我們需要儲存逆序對的數量,當序列是倒序的時候逆序列是最多的,即對 n−1
+n−2
+n−3...+1
n-1 + n-2 + n -3 ... + 1
n−1+n−
2+n−
3...
+1==>> ∑i=
1nn\sum_^nn
∑i=1n
n 也就是 n(n
−1)2
\frac
2n(n−1
),當n為 1e5
1e51e
5 時,逆序對的數量為 5×1
09−5
×104
5\times10^9-5\times10^4
5×109−
5×10
4,已經超出int的範圍了所以我們應該用long或者long long存
時間複雜度 o(n
logn
)o(nlogn)
o(nlog
n)一共劃分 log
nlogn
logn
次區間,每一層都是n次,所以時間複雜度是 o(n
logn
)o(nlogn)
o(nlog
n)c++ **
#include
using
namespace std;
typedef
long
long ll;
const
int n =
1e5+10;
int n;
int a[n]
;ll merge_sort
(int q,
int l ,
int r)
}while
(i <= mid) temp[k ++
]= q[i ++];
while
(j <= r) temp[k ++
]= q[j ++];
for(
int i = l , j =
0; i <= r;
++ i ,
++ j) q[i]
= temp[j]
;return res;
}int
main()
ACWing 788 逆序對的數量
給定乙個長n nn的數列,計算其逆序對數量。輸入格式 第一行包含整數n nn,表示數列的長度。第二行包含n nn個整數,表示整個數列。輸出格式 輸出乙個整數,表示逆序對的個數。資料範圍 1 n 100000 1 le n le 100000 1 n 10 0000 思路是歸併排序 分治 先累加左右兩...
AcWing 788 逆序對的數量
題目描述 給定乙個長度為n的整數數列,請你計算數列中的逆序對的數量。逆序對的定義如下 對於數列的第 i 個和第 j 個元素,如果滿足 i j 且 a i a j 則其為乙個逆序對 否則不是。輸入格式 第一行包含整數n,表示數列的長度。第二行包含 n 個整數,表示整個數列。資料範圍 1 n 10000...
AcWing 788 逆序對的數量(C 演算法)
逆序對的定義如下 對於數列的第 i 個和第 j 個元素,如果滿足 i j 且 a i a j 則其為乙個逆序對 否則不是。輸入格式 第一行包含整數n,表示數列的長度。第二行包含 n 個整數,表示整個數列。輸出格式 輸出乙個整數,表示逆序對的個數。資料範圍 1 n 100000 輸入樣例 62 3 4...