错位排列
全错位排列最经典的问题是装错信封问题。
我们把信封问题转换一下:
对于 1 − n 1-n 1−n 共n个数字组成的序列中,每个数字仅出现一次,求每个数字跟位置完全不对应的总方案数。
- 对于第一个位置上的数字1它有
n
−
1
n-1
n−1 种方案数
- 对于第二个位置上的数字2有两种放法:
①.放到1的位置上:
这时候就是已经把1和2放置好,剩下 n − 2 n-2 n−2个位置 d p [ n − 2 ] dp[n-2] dp[n−2]
②.放到后面 n − 2 n-2 n−2个位置上
这种情况其实就转换到了放数字1的情况(只是总数减一)
它就相当于数字1已经放好了 还剩下 n − 1 n-1 n−1个位置和 n − 1 n-1 n−1个数,数字2不能在位置1处,也就是 d p [ n − 1 ] dp[n-1] dp[n−1]的状态。
初始化状态: d p [ 1 ] = 0 ( 只 有 一 个 数 字 ) , d p [ 2 ] = 1 ( 两 个 数 字 ) dp[1]=0(只有一个数字),dp[2]=1(两个数字) dp[1]=0(只有一个数字),dp[2]=1(两个数字)
转移 :第i个数有 i − 1 i-1 i−1种方案,会转移到两种状态。
d p [ i ] = ( i − 1 ) ∗ ( d p [ i − 1 ] + d p [ i − 2 ] ) ; dp[i]=(i-1)*(dp[i-1]+dp[i-2]); dp[i]=(i−1)∗(dp[i−1]+dp[i−2]);
实现代码: d p [ i ] 表 示 i 个 数 错 位 排 列 的 方 案 数 dp[i]表示i个数错位排列的方案数 dp[i]表示i个数错位排列的方案数
dp[1] = 0; dp[2] = 1;
for(int i=3; i<=maxn; i++){
dp[i] = (i-1) * (dp[i-1] + dp[i-2]) % mod;
}