Let n!%p be a special factorial where n! is divided by the maximum exponent of p that divides n!

n!%p=n!dp(n!)

Where dp(n!) is called Legendre’s Formula which is explained in detail in this article

Compute n!%p(modp) given that p is a prime number

First let’s write this special factorial explicitly

(1)n!%p=1β‹…2⋅…⋅(pβˆ’1)β‹…pβ‹…(p+1)⋅…⋅(2pβˆ’1)β‹…2pβ‹…(2p+1)⋅…⋅(kpβˆ’1)β‹…kpβ‹…(kp+1)⋅…⋅(nβˆ’1)β‹…npnp+np2+...

The number kp is a number that is divisible by p, we also see that k might be a composite number that could be divisible by p again

Now let’s first divide the equation by pnp which is exactly the number of multiples of p

n!%p=1β‹…2⋅…⋅(pβˆ’1)β‹…1β‹…(p+1)⋅…⋅(2pβˆ’1)β‹…2β‹…(2p+1)⋅…⋅(kpβˆ’1)β‹…kβ‹…(kp+1)⋅…⋅(nβˆ’1)β‹…npnp2+...

If we apply the modulo operation to each term except the multiples of p we have

n!%p=1β‹…2⋅…⋅(pβˆ’1)β‹…1β‹…1β‹…2⋅…⋅(pβˆ’1)β‹…2β‹…1β‹…2⋅…⋅(pβˆ’1)β‹…pβ‹…1β‹…2⋅…⋅(pβˆ’1)β‹…kppnp2+...β‹…1β‹…2⋅…⋅(nβˆ’1)β‹…n

NOTE: we’re not applying the modulo operator to each multiple of p because they don’t actually exist since there are no p factors in the equation, they are reduced with posterior divisions by pnpi

NOTE: the number kp described in (1) just denotes a multiple of p

We see that the expression 1β‹…2⋅…⋅(pβˆ’1) is repeated many times in the equation above + a product of some additional terms which don’t form an entire sequence, let c=1β‹…2⋅…⋅(pβˆ’1) then

n!%p=1cβ‹…2c⋅…⋅(pβˆ’1)cβ‹…pcβ‹…(p+1)c⋅…⋅(kpβˆ’1)cβ‹…kpcpnp2+...β‹…1β‹…2⋅…⋅(nβˆ’1)β‹…n

Since each c factor occurs in every contiguous sequence of length p there are exactly ⌊npβŒ‹ c factors, factoring c we have

n!%p=c⌊npβŒ‹β‹…1β‹…2⋅…⋅(pβˆ’1)β‹…pβ‹…(p+1)⋅…⋅(2pβˆ’1)β‹…2pβ‹…(2p+1)⋅…⋅(kpβˆ’1)β‹…kppnp2+...β‹…1β‹…2⋅…⋅(nβˆ’1)β‹…n

Note that the term multiplying c⌊npβŒ‹ is the same as (1), we now have to divide it by pnp2 which is exactly the number of multiples of p2 (NOTE: kp is a multiple of p but might/might not be a multiple of p2)

This observation leads to a recursive implementation

Complexity: O(p,logpn)

long long special_factorial_mod_p(long long n, long long p) {
  long long res = 1;

  // computation of c
  long long c = p-1;

  while (n > 1) {
    res = (res * binary_exponentiation_modulo_m(c, n / p, p)) % p;
    for (long long i = 2; i <= n % p; i += 1) {
      res = (res * (long long)i) % p;
    }
    n /= p;
  }
  return res % p;
}

Applications

Finding the value of nCr

We can quickly calculate the value of nCr, we can compute the maximum exponents of p in n!, (nβˆ’r)! and r!, let those numbers be pa, pb and pc then nCr can be expressed as

nCr=(pa⋅…pbβ‹…pc…)

Which means that nCr will be a multiple of p when aβˆ’bβˆ’c>0, if aβˆ’bβˆ’c=0 then the number is equal to

nCr=n!%p(nβˆ’r)!%pβ‹…r!%p

NOTE: aβˆ’bβˆ’c can never be less than zero, that would imply that nCr is not an integer

The denominator can be found using the modular multiplicative inverse of (nβˆ’r)!%p and r!%p

long long nCr_mod_p(int n, int r, int p) {
  int a = max_power_in_factorial(n, p);
  int b = max_power_in_factorial(n - r, p);
  int c = max_power_in_factorial(r, p);
  if (a > b + c) {
    return 0;
  }

  return (special_factorial_mod_p(n, p) *
    ((modular_multiplicative_inverse(special_factorial_mod_p(n - r, p), p) *
    modular_multiplicative_inverse(special_factorial_mod_p(r, p), p)) % p) % p);
}

Problems to solve