Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Binomial coefficient modulo 142857

How to calculate binomial coefficient modulo 142857 for large n and r. Is there anything special about the 142857? If the question is modulo p where p is prime then we can use Lucas theorem but what should be done for 142857.

like image 509
user1505986 Avatar asked Oct 28 '12 05:10

user1505986


3 Answers

You can actually calculate C(n,k) % m in O(n) time for arbitrary m.

The trick is to calculate n!, k! and (n-k)! as prime-power-vectors, subtract the two later from the first, and multiply the remainder modulo m. For C(10, 4) we do this:

10! = 2^8 * 3^4 * 5^2 * 7^1
 4! = 2^3 * 3^1
 6! = 2^4 * 3^2 * 5^1

Hence

C(10,4) = 2^1 * 3^1 * 5^1 * 7^1

We can calculate this easily mod m as there are no divisions. The trick is to calculate the decomposition of n! and friends in linear time. If we precompute the primes up to n, we can do this efficiently as follows: Clearly for each even number in the product 1*2*...*9*10 we get a factor of 2. For each fourth number, we get a second on and so forth. Hence the number of 2 factors in n! is n/2 + n/4 + n/8 + ... (where / is flooring). We do the same for the remaining primes, and because there are O(n/logn) primes less than n, and we do O(logn) work for each, the decomposition is linear.

In practice I would code it more implicit as follows:

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
}

This includes a Sieve of Eratosthenes, so the running time is nloglogn rather than n if the primes had been precalculated or sieved with a faster sieve.

like image 175
Thomas Ahle Avatar answered Sep 28 '22 07:09

Thomas Ahle


The algorithm is:

  • factorise the base into prime powers; 142857 = 3^3×11×13×37
  • compute the result modulo each prime power
  • combine the results using the Chinese Remainder Theorem.

To compute (n above k) mod p^q:

Source: http://www.dms.umontreal.ca/~andrew/PDF/BinCoeff.pdf, theorem 1

define (n!)_p as the product of numbers 1..n that are not divible by p

define n_j as n after erasing j least significant digits in base p

define r as n-k

define e_j as the number of carries when adding k+r, not counting the carries from j lowest digits, computing in base p

define s as 1 if p=2 & q>=3 and -1 otherwise

then (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) ) with each term of the concatenation computing one base-p digit of the result, lowest j computing the least significant non-zero digits.

like image 43
John Dvorak Avatar answered Sep 28 '22 09:09

John Dvorak


What's special about 142857 is that 7 * 142857 = 999999 = 10^6 - 1. This is a factor that arises from Fermat's Little Theorem with a=10 and p=7, yielding the modular equivalence 10^7 == 10 (mod 7). That means you can work modulo 999999 for the most part and reduce to the final modulus by dividing by 7 at the end. The advantage of this is that modular division is very efficient in representation bases of the form 10^k for k=1,2,3,6. All you do in such cases is add together digit groups; this is a generalization of casting out nines.

This optimization only really makes sense if you have hardware base-10 multiplication. Which is really to say that it works well if you have to do this with paper and pencil. Since this problem recently appeared on an online contest, I imagine that's exactly the origin of the question.

like image 26
eh9 Avatar answered Sep 28 '22 09:09

eh9