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

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

求有多少种 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(nm)

做法一:牛顿反演

那么,该断言:

求有多少种 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=0n(in)D(ni)=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=0n(in)D(ni)=i=0n(nin)D(ni)=i=0n(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=0n(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=0n(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=0n(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=0n(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=0n(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(nm)=m!n!i=0nm(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} nlimD(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_i\right| i=1nXi=Ui=1nXi

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

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

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

我们进行组合推理:

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

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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值