📜  查找nCr是否可被给定素数整除(1)

📅  最后修改于: 2023-12-03 14:55:32.175000             🧑  作者: Mango

查找nCr是否可被给定素数整除
简介

在组合数的计算中,经常需要判断组合数的值是否能被给定的素数整除。这个问题可以通过计算n!与r!(n-r)!的乘积,再求其在给定素数下的剩余系数来解决。

解决方法

Fermat小定理

我们可以利用Fermat小定理,即如果p为素数,则对于任何整数a,以下恒成立:

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

根据上式,如果我们要求C(n,r)模p的余数,可以使用下面的公式:

$$ \binom{n}{r} = \frac{n!}{r!(n-r)!} \equiv \frac{\prod_{i=r+1}^n i}{\prod_{i=1}^{n-r} i} \pmod{p} $$

由于p是素数,因此根据费马小定理,对于1<=i<=n-r,i与p互质,因此有:

$$ \prod_{i=1}^{n-r} i \equiv (n-r)! \pmod{p} $$

因此,有以下式子:

$$ \binom{n}{r} \equiv \frac{\prod_{i=r+1}^n i}{(n-r)!} \pmod{p} $$

Lucas定理

Fermat小定理只能用于p是素数的情况。对于p不是素数的情况,我们可以使用Lucas定理。Lucas定理是Fermat小定理在扩展到组合数的情况下的一种推广。

对于给定的n和r,设p的十进制表示中有k位,即$p=\sum_{i=0}^{k-1} d_i \times 10^i$,则有以下Lucas定理:

$$ \binom{n}{r} \equiv \binom{n_0}{r_0} \binom{n_1}{r_1} \cdots \binom{n_{k-1}}{r_{k-1}} \pmod{p} $$

其中,$n=n_0+n_1\times 10+n_2 \times 10^2 + \cdots + n_{k-1} \times 10^{k-1}$,$r=r_0+r_1\times 10+r_2 \times 10^2 + \cdots + r_{k-1} \times 10^{k-1}$。

通过Lucas定理,我们可以将组合数的计算转化为多个小范围内组合数的计算。对于一个范围内的组合数,可以使用预处理的方法提前算出来。

代码示例

Fermat小定理的实现

def fermat_comb(n, r, p):
    if r > n:
        return 0
    num = 1
    den = 1
    for i in range(n-r+1, n+1):
        num = (num * i) % p
    for i in range(1, r+1):
        den = (den * i) % p
    den_inv = pow(den, p-2, p)
    return (num * den_inv) % p

Lucas定理的实现

def factorials_mod_p(n, p):
    factorials = [1]
    for i in range(1, n+1):
        factorials.append((factorials[-1] * i) % p)
    return factorials

def binom_mod_p(n, r, p, factorials=None):
    if r > n:
        return 0
    if not factorials:
        factorials = factorials_mod_p(n, p)
    num = factorials[n]
    den = (factorials[r] * factorials[n-r]) % p
    den_inv = pow(den, p-2, p)
    return (num * den_inv) % p

def lucas_comb(n, r, p):
    if r > n:
        return 0
    if n < p:
        return binom_mod_p(n, r, p)
    res = 1
    while n and r and res:
        n_cur = n % p
        r_cur = r % p
        if n_cur < r_cur:
            return 0
        res = (res * binom_mod_p(n_cur, r_cur, p)) % p
        n //= p
        r //= p
    return res
总结

在计算组合数时,如果要求组合数模素数p的余数,可以利用费马小定理或Lucas定理,将组合数的计算转化为小范围内组合数的计算,以此避免大数的计算。