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

发布于 2024-10-10 18:20:04 字数 247 浏览 8 评论 0原文

我们如何在 C 或 C++ 中计算 (N 选择 K)% M 而不调用溢出?

对于特定情况,当N (4<=N<=1000)K (1<=K<=N)M = 1000003 >。

How can we computer (N choose K)% M in C or C++ without invoking overflow ?

For the particular case when N (4<=N<=1000) and K (1<=K<=N) and M = 1000003.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

所谓喜欢 2024-10-17 18:20:04

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

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

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

To compute (n choose k) % M, you can separately compute the nominator (n!) modulus M and the denominator (k!*(n - k)!) modulus M and then multiply the nominator by the denominator's modular multiplicative inverse (in M). Since M is prime, you can use Fermat's Little Theorem to calculate the multiplicative inverse.

There is a nice explanation, with sample code, on the following link (problem SuperSum):

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

旧伤还要旧人安 2024-10-17 18:20:04

由于 1000000003 = 23 * 307 * 141623,您可以计算(n 选择 k)mod 23、307 和 141623,然后应用中国提醒定理[1]。计算n!、k!时并且 (nk)!,您应该每一步都计算 mod 23、307 和 141623,以防止溢出。

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

一个小小的改进是计算 (n 选择 k) mod 141623 和 7061 (23 * 307) (编辑:但计算逆模 7061 可能有点棘手,所以我不会这样做)

我很抱歉为了我糟糕的英语。

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

Edit2:我发现的另一个潜在问题是计算 n 时! mod 23 (例如)它可能是 0,但这并不意味着 (n 选择 k) 是 0 mod 23,所以你应该计算 23 除了 n!, (nk)! 多少次和k!在计算之前(n选择k)。计算起来很简单,p 除以 n!正好是楼层(n/p) + 楼层(n/p²) + ... 次。如果碰巧 23 整除 n!除以 k 的次数相同!和 (nk)!,您每次都会继续计算 (n 选择 k) mod 23 除以 23 的每个倍数。这同样适用于 307,但不适用于 141623

Since 1000000003 = 23 * 307 * 141623 you can calculate (n choses k) mod 23, 307 and 141623 and then apply the chinese reminder theorem[1]. When calculating n!, k! and (n-k)!, you should calculate everythinng mod 23, 307 and 141623 each step to prevent overflow.

In this way you should avoid overflow even in 32bit machines.

A little improvement would be to calculate (n choses k) mod 141623 and 7061 (23 * 307) (edit: but it can be a little tricky to calculate the inverse modulus 7061, so I wouldn't do this)

I'm sorry for my poor English.

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

Edit2: Another potentially problem I've found is when calculating n! mod 23 (for example) it will probably be 0, but that doesn't implies that (n choses k) is 0 mod 23, so you should count how many times 23 divides n!, (n-k)! and k! before calculating (n choses k). Calculating this is easy, p divides n! exactly floor(n/p) + floor(n/p²) + ... times. If it happens that 23 divides n! the same times it divides k! and (n-k)!, the you proceed to calculate (n choses k) mod 23 dividing by 23 every multipler of it every time.The same applies for 307, but not for 141623

您可以使用您提供的链接中的递归公式并进行 mod M 的计算。

You could use the recursive formula from the link you gave and do the calculation mod M.

从此见与不见 2024-10-17 18:20:04

这是一个简单的例子:

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

也就是说,您只需对每个操作数和乘积应用模数,或者当它变得很大时就应用模数。最后,模数必须应用于整体结果。

Here is a simple example:

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

That is, all you need to apply modulus to every operand and product, or as soon as it becomes big a number. And last the modulus must apply to the overall result.

慢慢从新开始 2024-10-17 18:20:04

使用斯特林近似计算二项式系数。然后像往常一样计算模数即可。

Use Stirling's approximation to calculate the binomial coefficient. Then just calculate the modulus as usual.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文