[Tutorial] Binomial Coefficient mod Non‑Prime m (Easy Method)

Правка en4, от darkahmed, 2025-07-09 16:35:40

When I was making a problem, I needed to calculate $$$C_n^r$$$ modulo a non-prime big number. So, I found a simpler method I haven't seen shared, and I'm excited to explain it.

Prerequisites:

  • Modular arithmetic

  • Factorization

  • Binary exponentiation

  • Knowing $$$\binom{n}{r}$$$ and Euler's totient function

The problem is the modular inverse. We can get it for a number $$$x$$$ if and only if $$$x$$$ is coprime with the modulus. But in a lot of problems, we just need to undo a previous operation,

$$$C_5^3 = \frac{5!}{3! \cdot 2!}$$$. We delete one $$$3$$$ and two $$$2$$$s from $$$5!$$$.

So why have we never thought to store it in a frequency array?

My idea is that when multiplying, we use the modular arithmetic formulas, and when dividing, we will count the frequency of each prime number in the modulus and delete it from $$$n!$$$, So we need to first calculate $$$n!$$$ without the primes in the modulus and count the frequency for each prime. Then, when you need to know the answer, you can iterate over the frequency array :)

But what if I divided $$$\frac{1}{2}$$$? It will not even happen, so what is the meaning of $$$\frac{1}{2}$$$?

I think it looks like imaginary numbers. $$$\sqrt{−1}^2 = −1$$$. It's easy to understand :)

We will find the prime factors of a number with any method (normal factorization is good enough). The modular inverse for a coprime number is $$$x^{phi(mod) - 1}$$$ (it's not working in power towers, but here I think it's enough here), $$$phi(x)$$$ is a multiplicative function you can easily calculate in $$$O(\sqrt{n})$$$.

So we can imagine a number, let's call him imaginary-modular-integer (imint), and make the necessary operations only (I mean * and /, no need for *= and /=).

Note: if you need to divide after adding, my trick will never work unless you make it better :) (tell me if you did).

You can see the code here:

My Code

After using this code as a template (please understand it first, don't just copy it!), you can write this:

dp[0].build(m);
for (int i = 1; i <= n; i++) dp[i] = i * dp[i - 1];

It will add $$$\lg(\lg(n))$$$ to the time complexity :(

When you need to calculate the answer, you can use $$$real()$$$ function.

Important Note: Do not write

dp[n] / (dp[r] * dp[n - r]);

. Instead, you should use:

(dp[n] / dp[r] / dp[n - r]).real();

It's not hard and pretty cool. If you know stars and bars and sieve, you can try to solve the easy version of my problem: Invitation

These are hardest two problems from Today's contest in Asyut Hack Club :)

Теги binomial, combinatorics, number theory

История

 
 
 
 
Правки
 
 
  Rev. Язык Кто Когда Δ Комментарий
en8 Английский darkahmed 2025-09-27 18:27:54 17
en7 Английский darkahmed 2025-09-27 18:27:07 533
en6 Английский darkahmed 2025-07-09 23:42:24 8
en5 Английский darkahmed 2025-07-09 16:38:19 4 Tiny change: 'These are hardest ' -> 'These are the hardest '
en4 Английский darkahmed 2025-07-09 16:35:40 3
en3 Английский darkahmed 2025-07-09 16:31:25 252 (published)
en2 Английский darkahmed 2025-07-08 00:30:12 57
en1 Английский darkahmed 2025-07-08 00:24:34 5203 Initial revision (saved to drafts)