計蒜客 排序

2021-10-04 00:00:59 字數 3292 閱讀 9823

計蒜客 排序

你需要分析排序演算法,將 n

nn 個互不相同的整數,通過交換兩個相鄰的元素使得數列有序的 最少交換次數。

比如,原數列為: 9,1

,0,5

,49,1,0,5,4

9,1,0,

5,4 排序後的數列為: 0,1

,4,5

,90,1,4,5,9

0,1,4,

5,9。

輸入格式

第一行乙個整數 n(n

≤500000

)n(n\leq500000)

n(n≤50

0000

)。接下來 n

nn 行,每行乙個整數 ai(

ai≤1

09)a_i(a_i\leq10^9)

ai​(ai

​≤109)。

591054

輸出格式

輸出乙個整數,表示操作次數。

6
樹狀陣列

離散化這是一道用樹狀陣列做的題,還要用到離散化的技巧。

一次有效的交換意味著什麼呢?

為了使序列有序,一次有效的交換應該是後乙個較小的數與他前乙個較大的數交換,那麼單獨乙個數字的交換次數,應該是這個數字前面比它大的數字的個數。

換句話說,當乙個數字出現的時候,出現在它左邊且比它大的數字的個數,就是當出現到這個數字為止(這個數字右邊的數字還沒出現)時,這個數字要到正確位置上交換的次數。

對每乙個位置上的數字累加這樣的次數,就是答案。

更一般的,令初始sum = 0,對於第 i 個數字,出現在它左邊且比它大的數字的個數如果是 x,就令sum += x,遍歷所有的數字,最後得到的累加和,就是答案。

現在剩乙個問題:怎麼知道出現在左邊的、比自己大的數字有多少?

對於遍歷到的第 i 個數字(記為 x),如果在遇到它的時候,單點更新樹狀陣列change(x),改變的動作是加 1,即計數,即令 x 出現的次數加 1,那麼,對於getsum(x)操作,就是求出從 1 到 x 的數字一共出現了多少次,即,不小於 x 的數字有多少個。

當我們得知了這個結果以後,由於出現在 x 右邊的數字是還沒有遇到的,所以,不小於 x 的數字都出現在 x 的左邊,那就可以簡單地使用i + 1 - getsum(x)得到出現在 x 左邊、比自己大的數字的個數。

這個公式是顯然成立的:對於第 i 個數字,目前已經出現的所有數字一共是 i + 1 個,在這些數字裡,不小於 x 的有getsum(x)個,所以,大於 x 的有i + 1 - getsum(x)個。並且,這些數字要麼是 x 本身,要麼出現在 x 的左邊。

累加所有的i + 1 - getsum(x),得到答案。

scanf

("%d"

,&n)

;for

(int i =

0; i < n; i++

)printf

("%d"

, ans)

;

但是,由於數字範圍實在是太大了,我們需要用到離散化的技巧,即將大範圍的數字對映到小範圍,因為我們只關心數字之間值的大小關係,而不關心具體的數值。

for

(int i =

0; i < n; i++

)

對於 c++,可以使用unique()函式來去重,首先對dis陣列排序,然後去重,得到去重後的長度length。在去重後的陣列中,用二分查詢x[i]所在的位置,並用這個位置作為x[i]離散化後的值。

sort

(dis, dis + n)

;// 對資料排序

int length =

unique

(dis, dis + n)

- dis;

// 利用 unique 去重,使大小與下標對應,並得到去重後的長度

for(

int i =

0; i < n; i++

)

之後的操作與之前類似,遍歷 x 陣列,change(x[i]),並計算ans += i + 1 - getsum(x[i])

最後要注意一下,anslong long範圍的。

以及提一句,uniquelower_bound返回值都是long long int,直接降級到int是一種不好的做法。

#include

using

namespace std;

int n =0;

const

int max_n =

500007

;int c[max_n]=;

// 樹狀陣列

int x[max_n]=;

// 記錄原始資料

int dis[max_n]=;

// 離散化資料

long

long ans =0;

intlowbit

(int x)

intgetsum

(int x)

return res;

}void

change

(int x)

}int

main()

sort

(dis, dis + n)

;// 對資料排序

int length =

unique

(dis, dis + n)

- dis;

// 利用 unique 去重,使大小與下標對應,並得到去重後的長度

計蒜客 排序

大家知道,給出正整數 nn,則 11 到 nn 這 nn 個數可以構成 n n 種排列,把這些排列按照從小到大的順序 字典順序 列出,如 n 3n 3 時,列出 text1 2 3,1 3 2,2 1 3,2 3 1,3 1 2,3 2 1 六個排列。蒜頭君給出某個排列,求出這個排列的下 kk 個排...

計蒜客 字母排序

題目描述 例如我們正常的字母排列順序是abcdefg xyz,代表a b c x y z abcd efg hhh ihg四個字串的最長不降子串行的長度分別為4 3 3 1 輸入格式 第1,2行為字串含義如題描述 輸出格式 輸出答案含義如題描述 1 第二行長度 255 樣例輸入 abcdefghij...

計蒜客 成績排序

計蒜客 成績排序 小蒜給出了班裡某門課程的成績單,請你按成績從高到低對成績單排序輸出,如果有相同分數則名字字典序小的在前。輸入格式 第一行為 n 0 n 20 表示班裡的學生數目 接下來的 n行,每行為每個學生的名字和他的成績,中間用單個空格隔開。名字只包含字母且長度不超過 20,成績為乙個不大於 ...