概述
错排问题、错排数与牛顿反演
求有多少种 1 1 1 到 n n n 的排列 a a a,满足序列恰好有 m m m 个位置 i i i,使得 a i = i a_i = i ai=i。
我们定义错排数 D ( n ) D(n) D(n),有有多少种 1 1 1 到 n n n 的排列 a a a,满足序列恰好有 0 0 0 个位置 i i i,使得 a i = i a_i = i ai=i。
那么原答案为:
( n m ) D ( n − m ) binom{n}{m}D(n - m) (mn)D(n−m)
做法一:牛顿反演
那么,该断言:
求有多少种 1 1 1 到 n n n 的排列 a a a,满足序列恰好有 m m m 个位置 i i i,使得 a i = i a_i = i ai=i。
将是所有排列 n ! n! n!的一个划分,所以:
∑ i = 0 n ( n i ) D ( n − i ) = n ! sum_{i = 0}^{n}binom{n}{i}D(n - i) = n! i=0∑n(in)D(n−i)=n!
即:
∑ i = 0 n ( n i ) D ( n − i ) = ∑ i = 0 n ( n n − i ) D ( n − i ) = ∑ i = 0 n ( n i ) 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 = 0 n ( − 1 ) i ( n i ) 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 = 0 n ( − 1 ) i ( n i ) 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 = 0 n ( − 1 ) i ( n i ) 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 = 0 n ( − 1 ) i ( n i ) 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 = 0 n ( − 1 ) i 1 i ! D(n) = n! sum_{i = 0}^{n} (-1)^i frac{1}{i!} D(n)=n!i=0∑n(−1)ii!1
此为错排数公式
那么,原问题的答案为:
( n m ) D ( n − m ) = n ! m ! ∑ i = 0 n − m ( − 1 ) i 1 i ! 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 infty n→∞的时候, D ( n ) D(n) D(n)有个近似模拟为:
lim n → ∞ D ( n ) = n ! e lim_{n to infty} D(n) = frac{n!}{e} n→∞limD(n)=en!
那么错排的概率:
lim ∞ P = 1 e lim_{infty} P = frac{1}{e} ∞limP=e1
错排问题还有很多特性,例如数学期望,方差等。
做法二:容斥原理
我们定义集合 X k X_k Xk为满足 a k = k a_k=k ak=k的排列的集合,当 n = 3 n=3 n=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 ) } 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 = 1 n X i ‾ ∣ = ∣ U ∣ − ∣ ⋃ i = 1 n X i ∣ left|bigcap_{i=1}^n overline{X_i}right| = |U| - left|bigcup_{i=1}^n X_iright| ∣∣∣∣∣i=1⋂nXi∣∣∣∣∣=∣U∣−∣∣∣∣∣i=1⋃nXi∣∣∣∣∣
我们对右侧进行容斥展开即可。
做法三:错排数的递推公式
除了上述容斥公式外,我们考虑错排数的递推公式。
我们进行组合推理:
排列 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4的错排数,那么我们想, 1 1 1可以放在 2 , 3 , 4 2,3,4 2,3,4的位置上,我们考虑把 1 1 1放在 2 2 2的位置上,此时 2 2 2可以放在 1 1 1的位置上,那么答案数为 D ( n − 2 ) D(n - 2) D(n−2), 2 2 2也可以不放在 1 1 1的位置上,此时通过合理推论 1 1 1的位置可以看做是 2 2 2的位置,那么此时的答案为 D ( n − 1 ) D(n - 1) D(n−1),并且 1 1 1可以放在 n − 1 n - 1 n−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("%lldn", ans);
}
return 0;
}
最后
以上就是苹果翅膀为你收集整理的错排问题、错排数与牛顿反演错排问题、错排数与牛顿反演的全部内容,希望文章能够帮你解决错排问题、错排数与牛顿反演错排问题、错排数与牛顿反演所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复