为n(10 ^ 9)的大值计算nCr mod m(n选择r)

时间:2012-10-30 19:53:53

标签: modulo ncr

现在CodeSprint 3已经结束,我一直想知道如何解决这个问题。我们需要简单地针对r和n的大值计算nCr mod 142857(0 <= n <= 10 ^ 9; 0 <= r <= n)。我使用递归方法,通过min(r,n-r)迭代来计算组合。结果证明这不够有效。我尝试过几种不同的方法,但它们似乎都不够高效。有什么建议吗?

1 个答案:

答案 0 :(得分:8)

对于非素数mod,使用一般Lucas定理对因子(142857 = 3 ^ 3 * 11 * 13 * 37)进行因子并计算模型的每个素因子的C(n,k)mod p ^ q,并且用中国剩余定理将它们组合起来。

例如,C(234,44)mod 142857 = 6084,然后

  • C(234,44)mod 3 ^ 3 = 9
  • C(234,44)mod 11 = 1
  • C(234,44)mod 13 = 0
  • C(234,44)mod 37 = 16

中国剩余定理涉及找到x这样

  • x = 9 mod 3 ^ 3
  • x = 1 mod 11
  • x = 0 mod 13
  • x = 16 mod 37

结果是x = 6084。

实施例

C(234,44)mod 3 ^ 3

首先将n,k和n-k转换为基础p

n = 234_10 = 22200_3

k = 44_10 = 1122_3

r = n-k = 190_10 = 21001_3

接下来找到承载次数

e[i] = number of carries from i to end
e   4 3 2 1 0
        1 1
r   2 1 0 0 1
k     1 1 2 2
n   2 2 2 0 0

现在创建一般卢卡斯所需的阶乘函数

def f(n, p):
    r = 1
    for i in range(1, n+1):
        if i % p != 0:
            r *= i
    return r

由于q = 3,您将一次仅考虑基本p表示的三位数

所以

f(222_3, 3)/[f(210_3, 3) * f(011_3, 3)] *
f(220_3, 3)/[f(100_3, 3) * f(112_3, 3)] *
f(200_3, 3)/[f(001_3, 3) * f(122_3, 3)] = 6719344775 / 7

现在

s = 1 if p = 2 and q >= 3 else -1

然后

p^e[0] * s * 6719344775 / 7 mod 3^3
e[0] = 2
p^e[0] = 3^2 = 9
s = -1
p^e[0] * s * 6719344775 = -60474102975

现在你有了

-60474102975 / 7 mod 3^3

这是线性同余,可以用

解决
ModularInverse(7, 3^3) = 4
4 * -60474102975 mod 27 = 9
因此,C(234,44)mod 3 ^ 3 = 9