【NOIP2012模擬10.29】排列 一題總結
題目大意:在n的全排列裡找出第k大的全排列並統計出在這個全排列裡有多少個數滿足這個數是Index數,且這個數所對應的下標位置也是Index數.(Index數是指這個數完全是由4和7組成的正整數)
分析:
30分做法:
暴力遞迴求解第k大的全排列,並統計Index數個數.
時間複雜度接近O(n!)
100分做法:
因為n<=10^9,這是一個非常大的數,但是又由於k<=10^9,顧可以看出我們無需考慮n的所有位數.
舉例:
當n=5的時候,k等於6,很明顯只對n的後三位有改變.
1 2 3 4 5
1 2 3 5 4
1 2 4 3 5
1 2 4 5 3
1 2 5 3 4
1 2 5 4 3
因為後面三位能組成3!種排列.
同理,對於k<=10^9,只可能對n後面十三位有影響,前面位數上的數肯定是按照1,2,3,4……這樣子排列的.
明白了這點,我們可以把n分類討論,分兩部分:
會被k影響到的,設為後j位
不會被k影響到的,前n-j位
對於前n-j位因為是按1,2,3......這樣排列下去,每個數與每個數所對應的位置都相等,所以我們只需把所有是Index數的數存起來,然後直接判斷是否小於等於n-j即可.
那麼對於後j位我們怎麼做呢?
這樣要運用到康託逆展開.
那麼康託逆展開的具體方法是什麼呢?
設我們要求第k大的全排列,先把後j位看成j,j+1,j+2……這樣子排列的數.
則求第i位數可表示為:
t ÷ (w-1)! = x …… y
(t的初值是k-1,w的初值則是j-1,)
這裡的x和y分別代表,之前記算全排列時i-1位當中沒有求過的數所組成的數列中第x+1個大的數則為全排列的第i位,y則表示計算第i+1位當中t的值,w很明顯每次計算時是遞減的.
這樣子做一遍效率是O(n²)的.
可以在題目規定時間內找出第K大的全排列.
找出全排列之後,我們只需再掃一遍判斷這j個數和其對應的下標是否都是Index數即可.
那這樣子的時間複雜度應最壞為O(2^(log10n)+2^(log10n)*m+m²)(之前證明過m最大不會超過13)
做出這一題後對康拓逆展開應該有一個初步的認知了,但是還需弄懂康拓逆展開的原理才能印象更加深刻.
(以下證明不僅不嚴謹,且很多話語表達不清,只是自己的一些微弱理解,請大神自動跳過)
設我們要求的是n的全排列當中第k大的全排列,每次是求第i位上的數.
根據公式
t ÷ (w-1)! = x …… y
這裡(w-1)!是後i+1位上還有多少個數.
那麼t應該怎麼表達會更加清晰呢?
轉眼一看,t好像指的是在求第i位時,我們要找的第t大的全排列.
但因為t的初值是K-1,所以t更形象的可以表達成我要求當前第i位時第t-1大的全排列.
那麼計算出來的x所表示的第x+1大的數為全排列第i位上的數的正確性怎麼證明呢,想弄懂這個,首先得明白x所代表的是什麼?
x所代表的是全排列第i位上比這個數小的數有x個,那麼第x+1大的數就是第全排列第i位上的數就可以很容易的證明了.
而y為什麼是下次求值的t,則也可以通過如上一番討論輕鬆理解了.