1. 程式人生 > >【NOIP2012模擬10.29】排列 一題總結

【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,則也可以通過如上一番討論輕鬆理解了.