POJ 重要逆序對

2021-08-21 12:59:23 字數 2344 閱讀 8966

總時間限制:  10000ms       單個測試點時間限制: 1000ms

記憶體限制:    65536kb

描述

給定n個數的序列a1,a2,...an,定義乙個數對(ai, aj)為「重要逆序對」的充要條件為 i < j 且 ai > 2aj。求給定序列中「重要逆序對」的個數。

輸入

第一行為序列中數字的個數n(1 ≤ n ≤ 200000)。

第二行為序列a1, a2 ... an(0 ≤a ≤ 10000000),由空格分開。

輸出

輸出乙個整數,為給序列中「重要逆序對」的個數。

樣例輸入

10

0 9 8 7 6 5 4 3 2 1

樣例輸出

16
提示

如果使用printf輸出long long型別,請用%lld

資料範圍

對於40%的資料,有n ≤ 1000。

本題的典型解法是採用歸併排序。相似題目為「求逆序對數」。

在"求逆序對數"中,歸併排序的核心**如下

void merge(int *s, int *temp, int startindex, int endindex, int mid)

else

k ++;

}while(i <= mid)

while(j <= endindex)

for(int i = startindex; i <= endindex; i ++)

}

但是本題所求為「重要逆序對數」,因此我在上機時的做法如下:

void merge(int *s, int *temp, int startindex, int endindex, int mid)

} }

j ++;

}else

k ++;

}while(i <= mid)

while(j <= endindex)

for(int i = startindex; i <= endindex; i ++)

}

但是很不幸的是,tle了。回來後,室友提醒,在裡面加了一重迴圈後,時間複雜度就不是o(nlogn)了,在最壞情況下,應該是o(n^2 logn)。上機時信心滿滿地以為加了break應該不會tle,但是...

室友的做法是建立乙個虛擬指標pointer,從startindex開始,一直指到mid結束。時間複雜度並不會增加。

譬如歸併(0, 6, 7, 8, 9)和(1, 2, 3, 4, 5)時,s[i]指向左邊部分,s[j]指向右邊部分。當pointer指向6,s[j] = 1 時,2 * 1<6;因此6右邊的7,8,9都是重要逆序;pointer指向6,s[j] = 2時,2 * 2 < 6;因此,6右邊的7,8,9都是重要逆序;pointer指向6,s[j] = 3時,2 * 3 = 6,因此需要加pointer右移一位,此時pointer指向的是7,2 * 3 < 7,因此 7右邊的8,9都是重要逆序......以此類推,對於每乙個s[j],都將pointer移動至s[pointer] > 2 * s[j]的位置i處。

顯然pointer最多隻需要移動 n / 2次(從startindex到mid處),因此不會增加複雜度。

完整**如下:

#include using namespace std;

long long sum = 0;

void merge(int *s, int *temp, int startindex, int endindex, int mid)

if(pointer != mid + 1)

j ++;

}else

k ++;

}while(i <= mid)

while(j <= endindex)

for(int i = startindex; i <= endindex; i ++)

}void mergesort(int *s, int *temp, int startindex, int endindex)

}int s[200005] = {};

int temp[400010] = {};

int main()

mergesort(s, temp, 0, n - 1);

cout << sum << endl;

return 0;

}

如果**有問題,還望指出。

poj 2299 求逆序對

題目大意 求逆序對 解題思路 分治法,類似於歸併排序。a 1.n 將原問題劃分為2個子問題a 1.n 2 a n 2 1.n 並且兩個子陣列已經排好序了,1.n 2的逆序對已經求好,n 2 1.n的逆序對也已經求好了 所以求兩個子問題之間的逆序對,在歸併排序的過程中,當a i a j 時,逆序對的數...

樹狀陣列求逆序對 POJ 2299 3067

前幾天開始看樹狀陣列了,然後開始找題來刷。首先是 poj 2299 ultra quicksort 這題是指給你乙個無序序列,只能交換相鄰的兩數使它有序,要你求出交換的次數。實質上就是求逆序對,網上有很多人說它的原理是氣泡排序,可以用歸併排序來求出,但我一時間想不出它是如何和歸併排序搭上邊的 當初排...

poj 2188 歸併排序求逆序對

題目比較繞,但是大意就是求逆序對 幫牛們解開纏繞在一起的繩子 此題允許o n2 但是nlogn就可以過。主要就是如何得到要排序的序列,main函式裡可以清晰看出來。下面是 include include include define m 1001 using namespace std int n,...