错排问题、错排数与牛顿反演

本文探讨了错排问题的数学概念,包括错排数D(n)的定义,即在1到n的排列中没有元素在正确位置上的排列数量。通过牛顿反演和容斥原理两种方法解析了如何计算恰好有m个元素在错误位置的排列数目,并给出了递推公式。此外,还展示了当n趋向于无穷大时,错排概率趋近于1/e的性质。最后,提供了一段C++代码实现计算错排数的算法。

错排问题、错排数与牛顿反演

求有多少种 111nnn 的排列 aaa,满足序列恰好有 mmm 个位置 iii,使得 ai=ia_i = iai=i

我们定义错排数D(n)D(n)D(n),有有多少种 111nnn 的排列 aaa,满足序列恰好有 000 个位置 iii,使得 ai=ia_i = iai=i

那么原答案为:

(nm)D(n−m) \binom{n}{m}D(n - m) (mn)D(nm)

做法一:牛顿反演

那么,该断言:

求有多少种 111nnn 的排列 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=0n(in)D(ni)=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=0n(in)D(ni)=i=0n(nin)D(ni)=i=0n(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=0n(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=0n(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=0n(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=0n(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=0n(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(nm)=m!n!i=0nm(1)ii!1

根据泰勒公式展开,当n→∞n \to \inftyn的时候,D(n)D(n)D(n)有个近似模拟为:

lim⁡n→∞D(n)=n!e \lim_{n \to \infty} D(n) = \frac{n!}{e} nlimD(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=1nXi=Ui=1nXi

我们对右侧进行容斥展开即可。

做法三:错排数的递推公式

除了上述容斥公式外,我们考虑错排数的递推公式。

我们进行组合推理:

排列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(n2)222也可以不放在111的位置上,此时通过合理推论111的位置可以看做是222的位置,那么此时的答案为D(n−1)D(n - 1)D(n1),并且111可以放在n−1n - 1n1个位置上,由此可见,递推公式为:

D(n)=(n−1)[D(n−1)+D(n−2)] D(n) = (n - 1) [D(n - 1) + D(n - 2)] D(n)=(n1)[D(n1)+D(n2)]

#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;
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值