错位排列相关

错排问题与自然底数
本文探讨了错排问题的定义与性质,包括错排数的递推公式与容斥原理求解方法,揭示了错排数与自然底数之间的数学联系。

一.错排问题与错排数.

错排问题:对于一个排列pip_ipi,有多少种重新排列的方法使得重排后的序列pi′p'_ipi满足对于任意位置iii都有pi≠pi′p_i\neq p'_ipi=pi.

容易发现这个问题中的方案数只与排列的长度有关,与具体在第iii个位置的pip_ipi无关,所以我们有了错排数这样一个概念.

错排数:对于一个长度为nnn的排列的错排数量,记为DnD_nDn.

关于错排数有一个小性质.

性质∑i=0n(ni)Di=n!\sum_{i=0}^{n}\binom{n}{i}D_i=n!i=0n(in)Di=n!.

证明:
考虑对于每一个iii(nn−i)Di\binom{n}{n-i}D_i(nin)Di表示nnn个数中选iii个数错排且n−in-ini个数不错排的方案数,显然求和后就是总排列数n!n!n!,于是就有:
n!=∑i=0n(nn−i)Di=∑i=0n(ni)Di n!=\sum_{i=0}^{n}\binom{n}{n-i}D_i=\sum_{i=0}^{n}\binom{n}{i}D_i n!=i=0n(nin)Di=i=0n(in)Di

证毕.


二.错排的递推公式.

求错排数的递推公式,可以通过分两类讨论:
1.已经有了前n−1n-1n1个数的错排数Dn−1D_{n-1}Dn1,现在要加入第nnn个数,可以把第nnn个数先放到第nnn个位置,然后随便与前面的一个数交换位置,方案数为(n−1)Dn−1(n-1)D_{n-1}(n1)Dn1.
2.已经有了前n−1n-1n1个数,只有一个位置kkk上是kkk,其它都是错排,那么加入的第nnn个数就必须与第kkk个位置交换,方案数为(n−1)Dn−2(n-1)D_{n-2}(n1)Dn2.

于是我们可以得到错排的递推公式1
Dn=(n−1)(Dn−1+Dn−2) D_n=(n-1)(D_{n-1}+D_{n-2}) Dn=(n1)(Dn1+Dn2)

在OI中用的最多的就是这个公式.

不过考虑一下是不是可以求个更简单的递推式?考虑转化一下式子:
Dn−nDn−1=−[Dn−1−(n−1)Dn−2]=(−1)2[Dn−2−(n−2)Dn−3]=(−1)3[Dn−3−(n−3)Dn−4]⋯=(−1)n−2[D2−2D1]=(−1)n[1−2∗0]=(−1)n D_n-nD_{n-1}=-[D_{n-1}-(n-1)D_{n-2}]\\ =(-1)^{2}[D_{n-2}-(n-2)D_{n-3}]\\ =(-1)^{3}[D_{n-3}-(n-3)D_{n-4}]\\ \cdots\\ =(-1)^{n-2}[D_2-2D_1]\\ =(-1)^{n}[1-2*0]\\ =(-1)^{n} DnnDn1=[Dn1(n1)Dn2]=(1)2[Dn2(n2)Dn3]=(1)3[Dn3(n3)Dn4]=(1)n2[D22D1]=(1)n[120]=(1)n

然后再重新转化回来得到错排的递推公式2
Dn=nDn−1+(−1)n D_n=nD_{n-1}+(-1)^n Dn=nDn1+(1)n



三.错排的容斥求解.

考虑错排数如何容斥?考虑枚举那些位置不动,直接大力容斥可以列出式子:
Dn=∑T∈[n](−1)∣T∣(n−∣T∣)! D_n=\sum_{T\in [n]}(-1)^{|T|}(n-|T|)!\\ Dn=T[n](1)T(nT)!

我们发现每一个集合TTT的贡献只与它的大小有关,所以可以化简式子:
Dn=∑i=0n(−1)i(ni)(n−i)!=∑i=0n(−1)i∗n!i!(n−i)!∗(n−i)!=∑i=0n(−1)i∗n!i!=n!∑i=0n(−1)ii! D_n=\sum_{i=0}^{n}(-1)^{i}\binom{n}{i}(n-i)!\\ =\sum_{i=0}^{n}(-1)^{i}*\frac{n!}{i!(n-i)!}*(n-i)!\\ =\sum_{i=0}^{n}(-1)^{i}*\frac{n!}{i!}\\ =n!\sum_{i=0}^{n}\frac{(-1)^{i}}{i!} Dn=i=0n(1)i(in)(ni)!=i=0n(1)ii!(ni)!n!(ni)!=i=0n(1)ii!n!=n!i=0ni!(1)i

于是我们也可以得到错排的通项公式
Dn=n!∑i=0n(−1)ii! D_n=n!\sum_{i=0}^{n}\frac{(-1)^{i}}{i!} Dn=n!i=0ni!(1)i

其实不直接考虑容斥,根据一种提到的性质进行二项式反演也可以推:
n!=∑i=0n(ni)DiDn=∑i=0n(−1)n−i(ni)i!Dn=n!∑i=0n(−1)ii! n!=\sum_{i=0}^{n}\binom{n}{i}D_i\\ D_n=\sum_{i=0}^{n}(-1)^{n-i}\binom{n}{i}i!\\ D_n=n!\sum_{i=0}^{n}\frac{(-1)^{i}}{i!} n!=i=0n(in)DiDn=i=0n(1)ni(in)i!Dn=n!i=0ni!(1)i

不过由于二项式反演的本质也是一种容斥,所以就没有单独列一块了.


四.错排与自然底数的关系.

我们看一下错排数的通项公式:
Dn=n!∑i=0n(−1)ii! D_n=n!\sum_{i=0}^{n}\frac{(-1)^i}{i!} Dn=n!i=0ni!(1)i

再来看一下ene^{n}en的泰勒展开:
en=∑i=0+∞nii! e^{n}=\sum_{i=0}^{+\infty}\frac{n^i}{i!} en=i=0+i!ni

我们代入一个n=−1n=-1n=1进去:
e−1=∑i=0+∞(−1)ii! e^{-1}=\sum_{i=0}^{+\infty}\frac{(-1)^i}{i!} e1=i=0+i!(1)i

有没有发现这两个式子非常像啊?

我们可以写出DnD_nDnnnn接近无穷大时的式子:
lim⁡n→+∞Dn=n!∑i=0n(−1)ii!lim⁡n→+∞Dnn!=∑i=0n(−1)ii!lim⁡n→+∞Dnn!=e−1lim⁡n→+∞n!Dn=e \lim_{n\rightarrow +\infty} D_n=n!\sum_{i=0}^{n}\frac{(-1)^i}{i!}\\ \lim_{n\rightarrow +\infty} \frac{D_n}{n!}=\sum_{i=0}^{n}\frac{(-1)^{i}}{i!}\\ \lim_{n\rightarrow +\infty} \frac{D_n}{n!}=e^{-1}\\ \lim_{n\rightarrow +\infty} \frac{n!}{D_n}=e\\ n+limDn=n!i=0ni!(1)in+limn!Dn=i=0ni!(1)in+limn!Dn=e1n+limDnn!=e

也就是说nnn越大时,一个长度为nnn的排列方案数与长度为nnn的错排方案数的比值越接近eee.

<think>嗯,用户想了解错位排列的递推公式以及如何用算法实现。首先,我需要回忆一下错位排列的定义和递推公式。根据引用中的信息,欧拉给出了递推公式,f(n) = (n-1)*(f(n-1) + f(n-2)),对吧?那这个公式的推导过程是怎样的呢?比如,当新增第n个元素时,它不能放在第n位,所以有n-1种选择。假设它放在第i位,那么分两种情况:原来的第i个元素放到第n位,剩下的n-2个元素错位排列,也就是f(n-2);或者原来的第i个元素不放到第n位,那么剩下的n-1个元素需要错位排列,即f(n-1)。这样两种情况相加,再乘以n-1种选择,得到递推式。 接下来,用户可能需要具体的算法实现。引用中的代码示例使用了动态规划的方法,初始化a[2]=1,a[3]=2,然后循环计算到n。要注意处理n=0或1的情况,返回0,对吗?比如当n=1时,没有错位排列的可能,所以结果为0。而n=2时,只有一种可能,交换两个元素。 用户可能还关心时间复杂度和空间复杂度。动态规划的方法时间复杂度是O(n),空间复杂度也是O(n),但如果只需要计算到某个n的值,可以优化空间,只保留前两个状态,这样空间复杂度变成O(1)。不过引用中的代码似乎用了数组来存储所有中间结果,可能更适合多次查询的情况,比如预处理后直接查表。 然后,用户的应用场景可能涉及组合数学问题,比如信封装或者排列问题中的约束条件。编程实现时需要注意大数问题,因为当n较大时,结果会迅速增长,可能需要使用大整数类型,如Python中的int可以自动处理,而C++中可能需要使用long long或者高精度库。 另外,用户可能对递推公式的数学证明感兴趣,或者如何从排列组合的角度理解这个递推关系。比如,可以通过数学归纳法来证明递推公式的正确性,或者举例说明n=4时的情况,如引用中给出的输出9,验证递推的正确性。 最后,需要确保代码示例正确,比如在Python中实现递推公式,处理边界条件,并测试几个例子,如n=4返回9,n=5返回44等。可能还需要对比递归和动态规划实现的效率,因为递归会有重复计算,而动态规划更高效。</think>### 错位排列递推公式与算法实现 #### 一、递推公式推导 错位排列(全错位排列)指长度为$n$的排列中,**所有元素都不在原始位置**的情况总数,记为$f(n)$。数学家欧拉给出的递推公式为: $$f(n) = (n-1) \cdot [f(n-1) + f(n-2)]$$ 其中初始条件为: - $f(0)=1$(空排列视为有效) - $f(1)=0$(单个元素无法错位) - $f(2)=1$(仅1种交换方式) **推导过程**: 1. 新增第$n$个元素时,该元素不能放在第$n$位,因此有$n-1$种位置选择(假设放在第$i$位) 2. 此时原第$i$位的元素有两种情况: - **情况1**:原第$i$位元素放在第$n$位 → 剩余$n-2$个元素错位排列,共$f(n-2)$种 - **情况2**:原第$i$位元素不放在第$n$位 → 剩余$n-1$个元素错位排列,共$f(n-1)$种 3. 综合两种情况,总数为$(n-1) \cdot [f(n-1)+f(n-2)]$[^1] #### 二、算法实现 ##### 动态规划法(时间复杂度$O(n)$,空间复杂度$O(n)$) ```python def derangement(n): if n == 0: return 1 dp = [0] * (n+1) dp[0], dp[1], dp[2] = 1, 0, 1 for i in range(3, n+1): dp[i] = (i-1) * (dp[i-1] + dp[i-2]) return dp[n] ``` ##### 空间优化版(空间复杂度$O(1)$) ```python def derangement_optimized(n): if n == 0: return 1 if n == 1: return 0 a, b = 0, 1 # f(1), f(2) for i in range(3, n+1): a, b = b, (i-1)*(a + b) return b ``` #### 三、应用场景 1. **密码学**:生成无固定位置的置换表 2. **组合数学**:信封问题、随机排列生成 3. **算法设计**:随机化算法中的位置扰动 4. **数据分析**:检验数据分布的随机性 #### 四、验证示例 ```python print(derangement(4)) # 输出9 print(derangement(5)) # 输出44 ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值