如何计算大n
和r
的二项式系数模数142857。 142857有什么特别之处吗?如果问题是模p
,其中p
是素数,那么我们可以使用卢卡斯定理但是应该为142857做什么。
答案 0 :(得分:13)
算法是:
计算(n above k) mod p^q
:
资料来源:http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf,定理1
将(n!)_p
定义为1..n
p
的乘积
在删除基座n_j
中的n
个最低有效数字后,将j
定义为p
将r
定义为n
- k
将e_j
定义为添加k+r
时的数量,而不计算来自j
最低位数的数据,以p
为基础进行计算
将s
定义为1
p=2 & q>=3
,-1
否则
然后(n above k) mod p^q := p^e_0 * s^e_(q-1) * concatenate(j=d..0)( (n_j!)_p / ((k_j!)_p*(r_j!)_p) )
,每个连接项计算结果的一个base-p数字,最低j
计算最不重要的非零数字。
答案 1 :(得分:12)
您可以在C(n,k) % m
时间内为任意O(n)
实际计算m
。
诀窍是将n!
,k!
和(n-k)!
计算为素数向量,稍后从第一个中减去两个,然后将余数乘以模m
。对于C(10, 4)
,我们这样做:
10! = 2^8 * 3^4 * 5^2 * 7^1
4! = 2^3 * 3^1
6! = 2^4 * 3^2 * 5^1
因此
C(10,4) = 2^1 * 3^1 * 5^1 * 7^1
由于没有分歧,我们可以轻松地计算mod m
。诀窍是在线性时间内计算n!
和朋友的分解。如果我们预先计算质数为n
,我们可以按如下方式有效地执行此操作:显然,对于产品1*2*...*9*10
中的每个偶数,我们得到2
因子。对于每个第四个数字,我们得到第二个,依此类推。因此,2
中n!
个因素的数量为n/2 + n/4 + n/8 + ...
(其中/
为地板)。我们对剩余的素数做同样的事情,并且因为O(n/logn)
素数小于n
,我们O(logn)
每个素数都有效,所以分解是线性的。
在实践中,我会更加隐含编码,如下所示:
func Binom(n, k, mod int) int {
coef := 1
sieve := make([]bool, n+1)
for p := 2; p <= n; p++ {
if !sieve[p] {
// Sieve of Eratosthenes
for i := p*p; i <= n; i += p {
sieve[i] = true
}
// Calculate influence of p on coef
for pow := p; pow <= n; pow *= p {
cnt := n/pow - k/pow - (n-k)/pow
for j := 0; j < cnt; j++ {
coef *= p
coef %= mod
}
}
}
}
return coef
}
这包括一个Eratosthenes筛,因此如果使用更快的筛子预先计算或筛分,则运行时间为nloglogn
而不是n
。
答案 2 :(得分:3)
142857的特殊之处在于7 * 142857 = 999999 = 10 ^ 6 - 1.这是由费马的小定理产生的因子,a = 10且p = 7,产生模数等价10 ^ 7 == 10 (mod 7)。这意味着你可以在大多数情况下使用模999999,并在最后除以7减少到最终模数。这样做的优点在于,对于k = 1,2,3,6,模式划分在10 ^ k形式的表示基础中非常有效。在这种情况下你所做的就是将数字组加在一起;这是casting out nines的概括。
如果你有硬件base-10乘法,那么这种优化才有意义。如果你不得不用纸和铅笔做这件事,那真的可以说它很好用。由于这个问题最近出现在网上竞赛中,我想这正是问题的根源。