先搬一下(戳)維基百科的康托展開(戳):
康托展開是乙個全排列到乙個自然數的雙射,常用於構建雜湊表時的空間壓縮。 康托展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。
由於是雙射 所以可以求n的全排列裡第k大的排列(逆康托展開)
(偽)計算原理: 從某個元素找後面比這個元素小的數的個數,再乘以這個位置每乙個數字能有的組合方法數(排列 / 階乘),得出只考慮從這一位開始到末尾比當前小的排列數,然後加起來就是康托展開求的數(追求難懂的巔峰...........看不懂就看看維基.........
公式:ai 是整數 且 0 <= ai
< i , 1 <= i <= n
ai 的意義:參悟栗子吧
栗子:
例如,357再貼一下(戳)nocow關於康托展開的一頁(戳),有**,看得懂就差不多了4129
68 展開為 98884
。 因為x=2*8!+3*7!+4*6!+2*5!+0*4!+0*3!+2*2!+0*1!+0*0!=98884
. 解釋:
排列的第一位是3,比3小的數有兩個,以這樣的數開始的排列有8!個,因此第一項為2*8!排列的第二位是5,比5小的數有1、
2、3、4,由於3已經出現,因此共有3個比5小的數,這樣的排列有7!個,因此第二項為3*7!以此類推,直至0*0!
逆康托展開並不是康托展開完全逆過來:
1.減去1,得到比該排列小的排列的數量
2.從高位算起:取摸對應位的階乘,得到在這一位後面比這一位小的數的個數(所以要注意前面比這一位的數小的要去除)
栗子:
如n=5,x=96時:再貼上忘了什麼時候寫的**:首先用96-1得到95,說明x之前有95個排列.(將此數本身減去!)
用95去除4!得到3餘23,說明有3個數比第1位小,所以第一位是4.
用23去除3!得到3餘5,說明有3個數比第2位小,所以是4,但是4已出現 過,因此是5.
用5去除2!得到2餘1,類似地,這一位是3.
用1去除1!得到1餘0,這一位是2.
最後一位只能是1.
所以這個數是45321.
1 typedef longdone!long
ll;2
const ll factorial[11] = ;
3int num[101
];4 ll cantorex(int
n)12
return
sum;13}
14 ll ucantorex(ll sum, int
n)26
for(int i = 1; i <= n; ++i)
27if(!num[i]) ans = ans * 10 +i;
28return
ans;
29 }
康托展開 康托逆展開
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 為當前未出現的...
康托展開 逆康托展開
康托展開 問題 給定的全排列,計算出它是第幾個排列 求序列號 方法 康托展開 對於乙個長度為 n 的排列 num 1 n 其序列號 x 為 x a 1 n i a 2 n 2 a i n i a n 1 1 a n 0 其中a i 表示在num i 1 n 中比num i 小的數的數量 includ...
康托展開 逆康托展開
用途 康托展開是一種雙射,用於排列和整數之間的對映,可用於排列的雜湊 康托展開 公式 i n1pi i 1 sum limits p i i 1 i n 1 pi i 1 其中p ip i pi 為第i ii個數構成的逆序的個數,n為排列數的個數 例 排列 2134 i n1pi i 1 sum l...