至於筆者為什麼寫這篇學習筆記,其實也沒有什麼特殊原因(cantorsort2919
相信大家都學過排列組合,我們記 \(p_n^n\) 或 \(a_n^n\) 為 \(1\sim n\) 的全排列;
並且,全排列還可以按照字典序進行排序,
舉個栗子,
\(a=\\)
\(b=\\)
其中 \(len_a,所以 \(a\) 的字典序小於\(b\)。
而康托展開(cantor expansion,ce),記錄的就是 \(1\sim n\) 全排列的排名。
讓筆者再舉乙個栗子:
\(a=\\)。
我們知道長為 \(5\) 的排列 \(\\) 大於以 \(1\) 為第一位的任何排列,以 \(1\) 為第一位的排列有 \(4!\) 種。
非常好理解。
但是對第二位的 \(5\) 而言,它大於第一位與這個排列相同的,而這一位比 \(5\) 小的所有排列。
不過我們要注意的是,這一位不僅要比 \(5\) 小,還要滿足沒有在當前排列的前面出現過,不然統計就重複了。
因此這一位為 \(1,3,4\),第一位為 \(2\) 的所有排列都比它要小,數量為 \(3\times 3!\)。
按照這樣統計下去,答案就是 \(1+4!+3\times 3!+2!+1=46\)。
注意,
我們統計的是排名,因此最前面要 \(+1\)。
注意到我們每次要用到 當前有多少個小於它的數還沒有出現,這裡可以用樹狀陣列統計比它小的數出現過的次數。
因為排列的排名和排列是一一對應的,所以康托展開滿足雙射關係,是可逆的。可以通過類似上面的過程倒推回來。
如果我們知道乙個排列的排名,就可以推出這個排列。
因為 \(4!\) 是嚴格大於 \(3\times 3!+2\times 2!+1\times 1!\) 的,所以可以認為對於長度為 \(5\) 的排列,排名 \(x\) 除以 \(4!\) 向下取整就是有多少個數小於這個排列的第一位。
用式子來表達,就是第一位記作 \(y\) 時,有:
\[y=\lfloor \frac\rfloor
\]推廣,即可得出,\(1\sim n\) 的全排列中,第 \(x\) 名的排列的第一位 \(y\) 的計算式子:
\[y=\lfloor \frac\rfloor
\]關於上文提到的「用樹狀陣列統計比它小的數出現過的次數」,其實也可以用線段樹來代替。(你想怎樣就怎樣,不關筆者的事
時間複雜度:\(o(n\log n)\)
康托展開 逆康托展開學習筆記
啊。好久沒寫了。可能是最後一篇學習筆記了吧 題目大意 給定序列求其在全排列中的排名 給定排名求排列。這就是康托展開 逆康托展開要幹的事了。下面依次介紹 一 康托展開 首先,知道它是幹嘛的。就是給定乙個全排列之中的序列,求其在整個全排列中的排名。解釋一下 考慮這個序列的第i位,對於這個序列,只有前i位...
康托展開學習筆記
引入 對於乙個1 n的排列,如果我們要想將它作為狀態儲存起來,一般都會開乙個大小為n n的n維陣列,但這樣的話經常會爆空間複雜度,但又想到1 n的排列最多只有n!個,遠小於n n,故考慮用乙個數代表乙個排列,壓縮空間。康托展開,就是將乙個排列對應成它在全排列中的序數,即這個排列在所有排列中從小到大排...
康托展開 康托逆展開
x a n n 1 a n 1 n 2 a i i 1 a 1 0 其中a i 為當前未出現的元素中是排在第幾個 從0開始 這就是康托展開。康托展開可用 實現。編輯 把乙個整數x展開成如下形式 x a n n 1 a n 1 n 2 a i i 1 a 2 1 a 1 0 其中a i 為當前未出現的...