📜  计算nCr%p |第三套(使用费马小定理)(1)

📅  最后修改于: 2023-12-03 15:27:58.189000             🧑  作者: Mango

计算nCr%p |第三套(使用费马小定理)

在计算组合数时,常常需要对大数取模。费马小定理可以帮助我们通过模数的逆元来实现快速取模,从而提高计算效率。

费马小定理

假设 $p$ 是一个质数,$a$ 是不是 $p$ 的倍数的任意整数,则有:

$$a^{p-1} \equiv 1 \pmod p$$

这个定理通常被用来解决取模的问题。如果我们要计算 $a^n \bmod p$,我们可以先使用费马小定理计算出模数 $p$ 的逆元 $r$,然后将 $a^n$ 乘以 $r$ 后再取模,即:

$$a^n \bmod p = a^n \cdot r \bmod p$$

其中:

$$r \equiv p-2 \pmod p$$

具体证明方法可以参考下面的链接:

计算组合数

假设我们要计算 $C_n^k \bmod p$,其中 $p$ 是一个质数,$n$ 和 $k$ 是两个整数。

我们可以先计算出 $n!$ 和 $k!$ 的阶乘再计算 $(n-k)!$ 的阶乘,最后使用快速幂算法计算 $n!$ 和 $(k!(n-k)!)^{-1}$ 的乘积。

务必注意,为了避免出现计算过程中中间结果超出模数范围的情况,我们需要使用 Lucas 定理将 $n$ 和 $k$ 转化为 $p$ 进制数,再进行相应的计算。

下面是使用费马小定理计算组合数的 Python 代码:

def power(a, b, p):
    res = 1 % p
    while b > 0:
        if b & 1:
            res = res * a % p
        a = a * a % p
        b >>= 1
    return res

def inverse(n, p):
    return power(n, p - 2, p)

def C(n, k, p):
    if k > n:
        return 0

    n_fact, k_fact, nk_fact = 1, 1, 1
    for i in range(1, n + 1):
        n_fact = n_fact * i % p
        if i <= k:
            k_fact = k_fact * i % p
        if i <= n - k:
            nk_fact = nk_fact * i % p

    return n_fact * inverse(k_fact * nk_fact % p, p) % p

其中 power 函数实现了快速幂算法, inverse 函数实现了计算 $n^{-1} \bmod p$ 的功能。函数 C(n, k, p) 返回 $C_n^k \bmod p$ 的值。

总结

费马小定理可以帮助我们通过模数的逆元来实现快速取模,从而提高计算效率。在计算组合数时,我们可以使用费马小定理来计算模数的逆元,然后进行乘除法运算。