康托展開 數論)

2022-01-30 13:32:34 字數 1582 閱讀 8169

標籤: 數學方法——數論

閱讀體驗:

康托展開是乙個全排列到乙個自然數的雙射,常用於構建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)!

第二位是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

所以比 34152 小的組合有61個,即34152是排第62。

**實現就很簡單了(其實找後面有幾個比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進製的數。思路如下 先準備求每一位的階乘,...