我们如何计算N选择K模数为素数而不溢出?

时间:2011-01-09 11:57:55

标签: c++ c algorithm math modulo

如何在不调用溢出的情况下在C或C ++中计算机(N choose K)%M?

对于 N(4 <= N <= 1000) K(1 <= K <= N) M = 1000003的特定情况

5 个答案:

答案 0 :(得分:13)

要计算(n选择k)%M,您可以分别计算分母(n!)模数M和分母(k!*(n - k)!)模数M,然后将分母乘以分母的模数乘法逆(M中)。由于M是素数,你可以使用费马的小定理来计算乘法逆。

在以下链接上有一个很好的解释,带有示例代码(问题SuperSum):

http://www.topcoder.com/wiki/display/tc/SRM+467

答案 1 :(得分:3)

由于1000000003 = 23 * 307 * 141623,你可以计算(n选择k)mod 23,307和141623,然后应用中文提醒定理[1]。在计算n!,k时!和(n-k)!,你应该计算每个步骤的每个模式23,307和141623,以防止溢出。

这样即使在32位机器上也应避免溢出。

稍微改进就是计算(n选择k)mod 141623和7061(23 * 307)(编辑:但计算反模数7061可能有点棘手,所以我不会这样做)< / p>

对不起我的英语很差。

[1] http://en.wikipedia.org/wiki/Chinese_remainder_theorem

Edit2:我发现的另一个潜在问题是计算n时! mod 23(例如)它可能是0,但这并不意味着(n choses k)是0 mod 23,所以你应该计算23除以n!,(n-k)的次数!和k!在计算之前(n选择k)。计算这很容易,p除以n!确切的楼层(n / p)+楼层(n /p²)+ ...次。如果它发生了23分n!同样它划分k!和(n-k)!,你继续计算(n选择k)mod 23每次乘以它的23乘以它。这同样适用于307,但不适用于141623

答案 2 :(得分:2)

您可以使用您提供的链接中的递归公式,并执行计算模型M.

答案 3 :(得分:1)

这是一个简单的例子:

(A * B * C) % N ... is equal to... ((A % N) *  (B % N) * (C % N)) % N;

也就是说,您需要将模数应用于每个操作数和产品,或者只要它变为大数字。最后,模数必须适用于整体结果。

答案 4 :(得分:-1)

使用Stirling's approximation计算二项式系数。然后像往常一样计算模量。