概念
摘自百度百科。
康託展開是一個全排列到一個自然數的雙射,常用於構建雜湊表時的空間壓縮。康託展開的實質是計算當前排列在所有由小到大全排列中的順序,因此是可逆的。
康託展開
逐位計算,考慮一個排列 \(1\sim i-1\) 位已經確定的貢獻。如果 \(i\) 位置填了比 \(a_i\) 小的數,\(i+1\sim n\) 無論怎麼填都是小的。所以可以得出計算公式:
\[\sum_{i=1}^n\left(\sum_{j=i+1}^n a_j<a_i\right)\times(n-i)!+1
\]
中間那個東西可以用樹狀陣列維護。
逆康託展開
觀察到 \(\left(\sum_{j=i+1}^n a_j<a_i\right)<n-i\),這也恰恰說明逆展開是唯一的。
對於每一位都可以計算出後面小於當前位的數量,因為一些數在之前已經用過了,所以要在樹狀陣列上二分。
P1088 [NOIP2004 普及組] 火星人
如何做到 \(O(n\log n)\)?
\(n\) 太大了,轉排名加上 \(m\) 再轉排列不現實。
康擴充開的實質是什麼?
如果遇見過一些奇怪的進位制應該可以想到,康擴充開其實就是階乘進位制,只不過每個位置的係數比較特殊,並不直接是該位置上的數值,而是後面數值小於該位置數值的個數。
考慮維護係數,顯然一種排列可以對應多個係數。
初始直接將 \(n\) 位置的係數加上 \(m\)。
接著就是要在保證排名不變的情況下調整係數至還原後排列合法。
先來看還原的過程。從前往後,和逆康託展開一樣搞,係數即逆康託展開中除出來的個數。
那就只要保證 \(i\) 位置的係數是小於等於 \(n-i\) 的即可。
誒好像證明了是階乘進位制
不斷進位就做完啦!