错排问题、错排数与牛顿反演
求有多少种 111 到 nnn 的排列 aaa,满足序列恰好有 mmm 个位置 iii,使得 ai=ia_i = iai=i。
我们定义错排数D(n)D(n)D(n),有有多少种 111 到 nnn 的排列 aaa,满足序列恰好有 000 个位置 iii,使得 ai=ia_i = iai=i。
那么原答案为:
(nm)D(n−m) \binom{n}{m}D(n - m) (mn)D(n−m)
做法一:牛顿反演
那么,该断言:
求有多少种 111 到 nnn 的排列 aaa,满足序列恰好有 mmm 个位置 iii,使得 ai=ia_i = iai=i。
将是所有排列n!n!n!的一个划分,所以:
∑i=0n(ni)D(n−i)=n! \sum_{i = 0}^{n}\binom{n}{i}D(n - i) = n! i=0∑n(in)D(n−i)=n!
即:
∑i=0n(ni)D(n−i)=∑i=0n(nn−i)D(n−i)=∑i=0n(ni)D(i)=n! \sum_{i = 0}^{n}\binom{n}{i}D(n - i) = \sum_{i = 0}^{n}\binom{n}{n - i}D(n - i) = \sum_{i = 0}^{n}\binom{n}{i}D(i) =n! i=0∑n(in)D(n−i)=i=0∑n(n−in)D(n−i)=i=0∑n(in)D(i)=n!
接下来,我们构造牛顿二项式反演:
∑i=0n(−1)i(ni)f(i)=g(n) \sum_{i=0}^n(-1)^i \binom{n}{i} f(i) = g(n) i=0∑n(−1)i(in)f(i)=g(n)
进行牛顿反演:
∑i=0n(−1)i(ni)g(i)=f(n) \sum_{i=0}^n(-1)^i \binom{n}{i} g(i) = f(n) i=0∑n(−1)i(in)g(i)=f(n)
故有
∑i=0n(−1)i(ni)D(i)(−1)i=n! \sum_{i = 0}^{n} (-1)^i \binom{n}{i} \frac{D(i)}{(-1)^i} = n! i=0∑n(−1)i(in)(−1)iD(i)=n!
反演后:
D(n)(−1)n=∑i=0n(−1)i(ni)i! \frac{D(n)}{(-1)^n} = \sum_{i = 0}^{n} (-1)^i \binom{n}{i} i! (−1)nD(n)=i=0∑n(−1)i(in)i!
化简得到:
D(n)=n!∑i=0n(−1)i1i! D(n) = n! \sum_{i = 0}^{n} (-1)^i \frac{1}{i!} D(n)=n!i=0∑n(−1)ii!1
此为错排数公式
那么,原问题的答案为:
(nm)D(n−m)=n!m!∑i=0n−m(−1)i1i! \binom{n}{m}D(n - m) = \frac{n!}{m!} \sum_{i = 0}^{n - m} (-1)^i \frac{1}{i!} (mn)D(n−m)=m!n!i=0∑n−m(−1)ii!1
根据泰勒公式展开,当n→∞n \to \inftyn→∞的时候,D(n)D(n)D(n)有个近似模拟为:
limn→∞D(n)=n!e \lim_{n \to \infty} D(n) = \frac{n!}{e} n→∞limD(n)=en!
那么错排的概率:
lim∞P=1e \lim_{\infty} P = \frac{1}{e} ∞limP=e1
错排问题还有很多特性,例如数学期望,方差等。
做法二:容斥原理
我们定义集合XkX_kXk为满足ak=ka_k=kak=k的排列的集合,当n=3n=3n=3时,有:
X1={(1,2,3),(1,3,2)}X2={(1,2,3),(3,2,1)}X3={(1,2,3),(2,1,3)} X_1=\{(1,2,3),(1,3,2)\} \\ X_2=\{(1,2,3),(3,2,1)\} \\ X_3=\{(1,2,3),(2,1,3)\} X1={(1,2,3),(1,3,2)}X2={(1,2,3),(3,2,1)}X3={(1,2,3),(2,1,3)}
使用容斥原理,我们的答案为:
∣⋂i=1nXi‾∣=∣U∣−∣⋃i=1nXi∣ \left|\bigcap_{i=1}^n \overline{X_i}\right| = |U| - \left|\bigcup_{i=1}^n X_i\right| ∣∣∣∣∣i=1⋂nXi∣∣∣∣∣=∣U∣−∣∣∣∣∣i=1⋃nXi∣∣∣∣∣
我们对右侧进行容斥展开即可。
做法三:错排数的递推公式
除了上述容斥公式外,我们考虑错排数的递推公式。
我们进行组合推理:
排列1,2,3,41,2,3,41,2,3,4的错排数,那么我们想,111可以放在2,3,42,3,42,3,4的位置上,我们考虑把111放在222的位置上,此时222可以放在111的位置上,那么答案数为D(n−2)D(n - 2)D(n−2),222也可以不放在111的位置上,此时通过合理推论111的位置可以看做是222的位置,那么此时的答案为D(n−1)D(n - 1)D(n−1),并且111可以放在n−1n - 1n−1个位置上,由此可见,递推公式为:
D(n)=(n−1)[D(n−1)+D(n−2)] D(n) = (n - 1) [D(n - 1) + D(n - 2)] D(n)=(n−1)[D(n−1)+D(n−2)]
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
#define FR freopen("in.txt", "r", stdin)
#define FW freopen("out1.txt", "w", stdout)
#define MOD 1000000007
ll INV[1000005];
ll U[1000005];
ll FAC[1000005];
ll fpow(ll a, ll b, ll mod)
{
ll ans = 1;
for (; b; b >>= 1, a = (a * a) % mod)
{
if (b & 1)
{
ans = (ans * a) % mod;
}
}
return ans;
}
ll inv(ll a, ll m)
{
// fermat's formual
return fpow(a, m - 2, m);
}
int main()
{
INV[0] = 1;
INV[1] = 1;
for (ll i = 2; i < 1000005; i++)
{
INV[i] = (INV[i - 1] * inv(i, MOD)) % MOD;
}
U[0] = 1;
for (ll i = 1; i < 1000005; i++)
{
ll k = INV[i];
if (i & 1)
{
U[i] = (U[i - 1] - k) % MOD;
}
else
{
U[i] = (U[i - 1] + k) % MOD;
}
}
FAC[0] = FAC[1] = 1;
for (ll i = 2; i < 1000005; i++)
{
FAC[i] = (FAC[i - 1] * i) % MOD;
}
int T;
scanf("%d", &T);
while (T--)
{
int n, m;
scanf("%d %d", &n, &m);
ll ans = ((FAC[n] * INV[m]) % MOD * U[n - m]) % MOD;
ans = (ans + MOD) % MOD;
printf("%lld\n", ans);
}
return 0;
}
本文探讨了错排问题的数学概念,包括错排数D(n)的定义,即在1到n的排列中没有元素在正确位置上的排列数量。通过牛顿反演和容斥原理两种方法解析了如何计算恰好有m个元素在错误位置的排列数目,并给出了递推公式。此外,还展示了当n趋向于无穷大时,错排概率趋近于1/e的性质。最后,提供了一段C++代码实现计算错排数的算法。
2694





