【问题标题】:Binomial coefficient modulo 142857二项式系数模 142857
【发布时间】:2020-11-16 00:30:05
【问题描述】:

如何计算大 nr 的二项式系数模 142857。 142857有什么特别之处吗?如果问题是模 p 其中p 是素数,那么我们可以使用卢卡斯定理,但对于 142857 应该做什么。

【问题讨论】:

  • 请注意,因式分解会有所帮助,因为您可以使用 CRT 并计算模 11、13、27 和 37 的系数。
  • 维基百科链接到关于Binary coefficients modulo prime powers的PDF
  • 我实现了主要的幂算法,它在 power=1 时给出了正确的答案,但是当 power!=1 时,它对某些输入给出了错误的答案,对一些输入给出了正确的答案。我猜我的代码有问题。
  • 对于任何感兴趣的人:here 是我在比赛期间接受的binomod 函数的实现。我在同一个文件中将它与crt_coprime 函数一起使用。

标签: algorithm math combinatorics binomial-coefficients


【解决方案1】:

您实际上可以在O(n) 时间内为任意m 计算C(n,k) % 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 的因子。对于每第四个数字,我们得到第二个,依此类推。因此n! 中的2 因子的数量是n/2 + n/4 + n/8 + ...(其中/ 是地板)。我们对剩余的素数做同样的事情,因为有小于nO(n/logn) 素数,并且我们对每个素数都做O(logn) 工作,所以分解是线性的。

在实践中,我会更隐含地编码如下:

func Binom(n, k, mod int) int {
    coef := 1
    sieve := make([]bool, n+1)
    for p := 2; p <= n; p++ {
        // If p is not sieved yet, it is a prime number
        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

【讨论】:

    【解决方案2】:

    算法是:

    • 将基地分解为素数; 142857 = 3^3×11×13×37
    • 以每个素数为模计算结果
    • 使用中国剩余定理组合结果。

    计算(n above k) mod p^q

    来源:http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf,定理 1

    (n!)_p定义为不能被p整除的数字1..n的乘积

    在删除基址p 中的j 最低有效位后,将n_j 定义为n

    r定义为n-k

    定义e_j为加k+r时的进位数,不计算j最低位的进位,以p为基数计算

    s 定义为1 如果p=2 &amp; q&gt;=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 计算最低有效的非零数字。

    【讨论】:

    • 我想知道这有多快。你试过编码吗?我想将它与我的答案因式分解n 进行比较。
    • @ThomasAhle 我还没有尝试实现它,但是如果你要计算大于几百个数字的阶乘,你需要等待一段时间。
    • 二项式是product [(k+1)..n]/product [1..(n-k)],所以你仍然需要除法,你不能对任意数字取模。这就是这个问题的全部意义,不是吗?
    【解决方案3】:

    142857 的特殊之处在于 7 * 142857 = 999999 = 10^6 - 1。这是由费马小定理产生的一个因子,其中 a=10 和 p=7,产生模等价 10^7 == 10 (模式 7)。这意味着您可以在大多数情况下以 999999 为模数,并通过在最后除以 7 来减少最终模数。这样做的好处是,对于 k=1,2,3,6,模除法在 10^k 形式的表示基础中非常有效。在这种情况下,您所做的就是将数字组加在一起;这是casting out nines 的概括。

    只有在硬件以 10 为底的乘法时,这种优化才真正有意义。这真的是说,如果你必须用纸和铅笔来做这件事,它会很好用。由于这个问题最近出现在一个在线比赛中,我想这正是问题的由来。

    【讨论】:

    • 999999 并不是一个比 142857 更适合使用的模数,所以我不明白这如何使问题更容易解决......无论如何你都需要 Granville
    • @NiklasB。您可以更轻松地手动进行计算。我想我从来没有说过这让软件实现变得更好。
    • 但问题是如何计算该值?在这种情况下,142857 并没有什么特别之处
    • 有人问这个问题:“142857有什么特别之处吗?”这就是我回答的问题。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-05-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-04-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多