解释以下算法以找到nCr模P

时间:2014-10-11 22:57:24

标签: algorithm factorial number-theory

我试图解决涉及模数为素数的大因子的问题,并在另一个解决方案中找到以下算法:

long long factMod (long long n, long long p)
{
    long long ans = 1;
    while (n > 1)
    {
        long long cur = 1;

        for (long long i = 1; i < p; i++)
        {
            cur = (cur * i) % p;
        }

        ans = (ans * modPow(cur, n/p, p)) % p;


        for (long long i = 1; i <= n % p; i++)
        {
            ans = (ans * i) % p;
        }

        n /= p;
    }

    return (ans % p);
}

long long nChooseK(long long n, long long k, long long p)
{
    int num_degree = get_degree(n, p) - get_degree(n - k, p);
    int den_degree = get_degree(k, p);
    if (num_degree > den_degree) { return 0; }

    long long nFact = factMod(n, p);
    long long kFact = factMod(k, p);
    long long nMinusKFact = factMod(n-k, p);

    long long ans = (((nFact * modPow(kFact, p - 2, p)) % p) * modPow(nMinusKFact, p - 2, p))%p;
    return ans;
}

我知道数论的基础知识,但似乎无法弄清楚它是如何工作的。

nChooseK函数似乎使用组合[n!/(n-k)!k!]的定义与使用费马小定理计算的模逆,来代替除法。但是,根据其中一个答案,factMod函数实际上并不计算阶乘。如果是这种情况,nChooseK功能如何工作?

1 个答案:

答案 0 :(得分:1)

是的,是的! ≡0mod p当且仅当n≥p,但factMod不计算n! mod p - 它计算n!/ p k mod p其中k是n!的素数因式分解中p的指数,或许为目的计算二项式系数。循环的迭代i(从0开始计数)计算那些因子1 ... n的贡献,其素因子化包括p i 。语句n /= p;产生p的倍数的子问题。

函数get_degree(n, p)可能在n!的素数因子分解中返回p的指数。如果get_degree(n, p) == get_degree(k, p) + get_degree(n - k, p),则分子和分母中的p因子完全取消,我们可以使用factMod来考虑其他因素。否则,组合的数量可以被p整除,所以我们返回0。

自(p-1)以来! ≡-1 mod Wilson's theorem,第一个内部循环是多余的。