2

I was asked the following question in an interview:

How to solve this: ((3000000!)/(30!)^100000)%(any prime no.)

I coded the C program for same using brute force, but I am sure that he was not expecting this. Any suggestions for the solutions?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
Gaurav
  • 1,005
  • 3
  • 14
  • 33
  • If "^" means "raise to the power", then I think that 3E6!/30!^1E5 is less than one. If you interpret "/" as "integer division" then we get 0, so it remains 0 after the modulo. – redtuna Jul 26 '13 at 17:58
  • Agreed, but the interviewer asked me to code this. May be he was expecting me to come up with some theorem. – Gaurav Jul 26 '13 at 18:01
  • 1
    answer ---> 10 PRINT "0". And then a whiteboard discussion about why. – redtuna Jul 26 '13 at 18:06
  • I think the answer is related to Lucas' theorem. Exploring same as of now. – Gaurav Jul 26 '13 at 18:11
  • Or perhaps he expected you to write a program to prove some fact that you need in the overall proof; perhaps showing that 30! is more than 1E6, or something like that. Perhaps t=1; for i in [ x+1 for x in range(30) ]: t=t*i; print(t) ? – redtuna Jul 26 '13 at 18:13
  • 2
    @redtuna You think wrong, `3e6!` has the same number but much bigger factors than `30! * 1e5`, so the quotient is not zero. – starblue Jul 26 '13 at 19:46
  • @starblue ah indeed, you're right – redtuna Jul 27 '13 at 00:58
  • Actually "the same number of factors in the numerator and denominator" is a hint how to solve it: Arrange the factors so that you can split the fraction into parts that are integers, and then multiply those integers modulo the prime. – starblue Jul 28 '13 at 07:09
  • @starblue the number of [distinct prime factors in `30!^100000`](http://stackoverflow.com/a/17916804/849891) (10) and `3000000!` (216816) is not the same, far from it. :) – Will Ness Jul 30 '13 at 05:13
  • Yes, but I didn't talk about *prime* factors, I mean the factors you get when you write down the factorial and exponentiation explicitly. (I'm sure you know that, but this is for the benefit of the others in the audience.) – starblue Jul 30 '13 at 06:32
  • @starblue Ah, *now* I get what you meant there - writing out the 3,000,000 terms in 1*2*3*...*3000000 and in (1*2*3*...*30) repeated 100,000 times. But that proves nothing because we can't know whether one even divides the other or not, just from *that*. :) To determine this, we must cancel out the *prime* factors in the two products. – Will Ness Jul 30 '13 at 09:08
  • @Will Ness No, we don't need to do that. Each consecutive segment of 30 numbers from n! is divisible by 30!. It's a similar argument to why binomial coefficients are integers. – starblue Jul 31 '13 at 04:56
  • @starblue Yes, right, interesting, thank you for that. Not immediately self-evident though... But we need the factorization anyway to calculate the result with any reasonable efficiency, right? – Will Ness Jul 31 '13 at 06:50
  • @Will Ness You can just use big integers, you will need at most `30 * 22` bits, which is not that much. – starblue Jul 31 '13 at 07:57
  • @starblue that's whole new answer then, someone should (?) add it. :) --- btw I never thought it needed a proof, that binomial coefficients are integers, because they appear in Pascal's triangle. – Will Ness Aug 01 '13 at 09:26

1 Answers1

1

3000000! = 1*2*3*4*5*..*8*...*16*...*24*...*32*...40*...*64*...*3000000

Can we count the number of 2s in the result? Yes, each power of 2 contributes one 2 to each of its multiples. So the total number of 2s in the factorization of n! is n/2 + n/4 + n/8 + n/16 + n/32 + ... where / is integer division and terms are summed up while they are greater than 0:

fnf n f = -- number of `f` factors in `n!`
  sum . takeWhile (>0) . tail . iterate (`div` f) $ n

(writing the pseudocode in Haskell). when f*f < n, there will be more than one entry to sum up. For bigger fs, there will be only one entry to sum, viz. n `div` f.

So the factorization of n! is found as

factfact n =    -- factorization of n! as [ (p,k) ... ] for n! = PROD p_i^k_i
  let
    (ps,qs) = span (\p-> p*p <= n) primes   -- (before, after)
  in
    [(f, fnf n f)   | f <- ps] ++
    [(f, n `div` f) | f <- takeWhile (<= n) qs]

Now, factorization of 30! has 10 factors:

> factfact 30
[(2,26),(3,14),(5,7),(7,4),(11,2),(13,2),(17,1),(19,1),(23,1),(29,1)]

The 100000th power of it just has each of its factor coefficients multiplied by 100000. When we take the factorization of 3000000!, its first few terms out of 216816 total, are:

> factfact 3000000 
[(2,2999990),(3,1499993),(5,749998),(7,499996),(11,299996),(13,249998),
 (17,187497),(19,166665),(23,136361),(29,107142),(31,99998), ... 

so after the division when we subtract the second from the first none are lacking nor cancelled out completely:

[(2,399990),(3,99993),(5,49998),(7,99996),(11,99996),(13,49998),
 (17,87497),(19,66665),(23,36361),(29,7142),(31,99998), ...

So for any prime less than 3000000 the remainder is 0. What if it is bigger, p > 3000000? Then, modular exponentiation mod p and multiplication mod p for this factorization, that we found above, must be used. There are plenty of answers about those, on SO.

Of course in the production code (for a non-lazy programming language) we wouldn't build the intermediate factorization list, but instead just process each prime below 3000000, one by one (there's no need for that with a lazy language).

Will Ness
  • 70,110
  • 9
  • 98
  • 181
  • It will be really helpful if you can please point to the most relevant answer present on SO for p>3000000 using modular exponentiation mod p. (This concept is new to me). – Gaurav Jul 29 '13 at 19:04
  • @Gaurav try [these answers](http://stackoverflow.com/search?q=user%3A448810+%5Bprimes%5D+is%3Aanswer+modular). Or [these](http://stackoverflow.com/search?q=user%3A1011995+%5Bprimes%5D+is%3Aanswer+modular). – Will Ness Jul 29 '13 at 19:06
  • 1
    @Gaurav you can just type "modular multiplication" or "modular exponentiation" in a search box here on SO at the top right corner of a page. The first (of 1088) that comes up, looks OK too. – Will Ness Jul 29 '13 at 19:12