1. 程式人生 > >關於錯排公式以及擴充套件的一些小結論

關於錯排公式以及擴充套件的一些小結論

錯排問題

存在一個排列 \(\{P_i\}\) ,求有多少個排列 \(\{S_i\}\) 滿足 \(\forall P_i \not = S_i\)

錯排公式

\(f(n)\) 為有 \(n\) 個元素的錯排個數,顯然 \(f(1) = 0, f(2) = 1\)

遞推公式

我們會有一個遞推公式:
\[ f(n) = (n - 1)(f(n - 2) + f(n - 1)) \]

考慮新加進來一個元素,肯定不能放到它原來的位置,那麼就是放到其他 \(n - 1\) 個位置中的一個。然後考慮另外一個被佔位置的元素,如果它填到當前這個位置那麼會剩下 \(n - 2\) 需要錯排那麼就是 \(f(n - 2)\)

,不填到當前這個位置那麼就剩下所有數都一起錯排 就是 \(f(n - 1)\)

容斥原理

這個顯然是滿足要求的一個計數,那麼我們就可以列舉“犯了幾個錯誤”,也就是有幾個會在原位。

\[ f(n) = \sum_{i=0}^{n} (-1)^{i} \frac{n!}{i!} \]

錯排擴充套件

我們在之前那個問題上擴充套件一點,我們可以使得其中 \(k\) 個不存在限制。(也就是這個 \(k\) 個位置可以不滿足 \(P_i \not = S_i\)

動態規劃

這個可以用一個神奇的 \(dp\) 去計數,令 \(dp_{i, j}\) 為前 \(i\) 個數,有 \(j\) 個不存在限制。

顯然對於 \(j = 0\) 的時候我們可以和錯排一樣轉移:
\[ dp_{i, 0} = (i - 1) (dp_{i - 1, 0} + dp_{i - 2, 0}) \]
那麼對於 \(j \ge 1\) 的時候考慮新填一個元素造成的局面:
\[ dp_{i, j} = dp_{i - 1, j - 1} + dp_{i, j - 1} \]
前面就是新填的元素放到自己位置,那麼就和 \(dp_{i - 1, j - 1}\) 的局面是一樣的了,後面就是放到其他任意一個位置那麼不難發現這個和 \(dp_{i, j - 1}\) 的局面是一樣的。

這樣就可以結束這個擴充套件問題了。(注意前面邊界問題就行了)

組合數學

其實應該可以更優秀地解決這個問題,因為可以發現 \(dp_{i, j}\)\(\displaystyle {j \choose i}\) 的遞推形式是一樣的,所以我們可以 \(O(n)\) 推出第一行並且預處理階乘及其逆元,那麼我們可以用一個組合數直接算上去就行了。

至於是否有更好的實現,我並不是很清楚。。。

ps: 本文來自 zhou888 在今天考試中推的神奇 \(dp\) ,很有啟發~