標籤: 數學方法——數論
閱讀體驗:
康托展開是乙個全排列到乙個自然數的雙射,常用於構建hash表時的空間壓縮。
設有n個數\((1,2,3,4,...,n)\),可以有組成不同(\(n!\)種)的排列組合,康托展開表示的就是是當前排列組合在n個不同元素的全排列中的名次。
假設有乙個排列
,需要你在它的全排列中,找到排名第m的那個排列
全排列的順序就是字典序越來越大的排列,和我們的next_permutation()
函式的順序一樣
首先,放乙個很重要的公式(暫時不需要理解,後面慢慢就懂了):
\[x=a[n]*(n-1)!+a[n-1]*(n-2)!+...+a[i]*(i-1)!+...+a[1]*0!
\]其中 $ ! $ 是階乘的意思
我們再看乙個**
你先不管它的康托展開那一欄,根據後面的講解再看
排列組合
名次康托展開
1231
0 * 2! + 0 * 1! + 0 * 0!
1322
0 * 2! + 1 * 1! + 0 * 0!
2133
1 * 2! + 0 * 1! + 0 * 0!
2314
1 * 2! + 1 * 1! + 0 * 0!
3125
2 * 2! + 0 * 1! + 0 * 0!
3216
2 * 2! + 1 * 1! + 0 * 0!
思考一下
為什麼當前數列是排在第x位而不是更靠前?
是不是因為有大數字占領了前面的小數字的位置,把小數字擠到了後面的位置上,所以字典序變大了
這個可以理解吧
那麼,我們來考慮每個大數字對整個排列的編號的影響
再舉個例子:在(1,2,3,4,5)5個數的排列組合中,計算 34152的康托展開值。
首位是3,則小於3的數有兩個,為1和2,a[5]=2,則首位小於3的所有排列組合為 a[0]*(5-1)!所以比 34152 小的組合有61個,即34152是排第62。第二位是4,則小於4的數有兩個,為1和2,注意這裡3並不能算,因為3已經在第一位,所以其實計算的是在第二位之後小於4的個數。因此a[4]=2
第三位是1,則在其之後小於1的數有0個,所以a[3]=0
第四位是5,則在其之後小於5的數有1個,為2,所以a[2]=1
最後一位就不用計算啦,因為在它之後已經沒有數了,所以a[1]固定為0根據公式:
x = 2 * 4! + 2 * 3! + 0 * 2! + 1 * 1! + 0 * 0!
= 2 * 24 + 2 * 6 + 1
= 61
**實現就很簡單了(其實找後面有幾個比v[i]小有各種方法log(n)!)
for(int i=1;i<=n;++i)//注意這裡i全部是正著列舉的
//所以下面的jc處是n-i
}} //暴力到極致了吧……
(數論十一)康托展開與逆康托展開
一.引出康托展開 動態規劃題有一類分支叫狀壓dp,意思就是把狀態壓縮為乙個二進位制陣列,然後轉為十進位制數儲存。一般n的大小不會超過20,因為20個狀態的組合就有2 20,也就是1e6種可能。對於一些題目,緊緊利用狀態壓縮,會發現狀態的組合數遠遠超過1e6的範圍,那時候我們沒有辦法在1s內遍歷出來,...
數學 數論 康托展開與逆康托展開
康托展開 可以理解為把乙個全排列對映到乙個數上面,因為全排列如果按照從小到大或者從大到小,肯定是有乙個確定的序列的。一般是從小到大的序列個數。我們就是要求出這個序列的位置。想法很簡答,就是求出前面比他小的個數就可以了。理解為乙個每位都是階乘進製的數轉化為10進製的數。思路如下 先準備求每一位的階乘,...
數學 數論 康托展開與逆康托展開
康托展開 可以理解為把乙個全排列對映到乙個數上面,因為全排列如果按照從小到大或者從大到小,肯定是有乙個確定的序列的。一般是從小到大的序列個數。我們就是要求出這個序列的位置。想法很簡答,就是求出前面比他小的個數就可以了。理解為乙個每位都是階乘進製的數轉化為10進製的數。思路如下 先準備求每一位的階乘,...