如何计算二项式系数模142857大型n
和r
有什么特别之处142857? 如果问题是模p
,其中p
为素数,那么我们就可以用卢卡斯定理,但我应该为142857来完成。
Answer 1:
该算法是:
- factorise基地为主要力量; 142857 = 3 ^ 3×11×13×37
- 计算的结果每一个模素数幂
- 结合使用中国剩余定理的结果。
为了计算(n above k) mod p^q
:
来源: http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf ,定理1
定义(n!)_p
为数字产品1..n
不可由divible 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) )
其结果的级联计算一个基-对位的每个术语,最低j
计算所述至少显著非零数字。
Answer 2:
实际上,你可以计算C(n,k) % m
在O(n)
时间任意m
。
诀窍是计算n!
, k!
和(nk)!
如黄金功率矢量,从第一减去两个以后,和乘法剩余模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
}
这包括埃拉托色尼的筛子,使运行的时间nloglogn
而非n
如果素数已预先计算或以更快的筛进行筛分。
Answer 3:
有什么特别142857是7 * 142857 = 999999 = 10 ^ 6 - 1,这是源于费马用= 10,P = 7小定理,产生了模块化等值10 ^ 7 = = 10(MOD 1/7 )。 这意味着你可以工作模999999大部分并在最后7分降低到最终模量。 这样做的优点是,模块划分的形式是10 ^ k代表K = 1,2,3,6的代表性碱基非常有效的。 所有你在这种情况下做的就是添加数字集中到一起; 这是一个泛化去九法 。
这种优化唯一真正意义,如果你有硬件基础-10乘法。 这实在是说,它工作得很好,如果你有纸和铅笔做到这一点。 因为这个问题最近出现了一个在线竞赛,我想这也正是问题的起源。