When I was making a problem, I needed to calculate $$$C_r^n$$$ 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_3^5 = \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:
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 the hardest two problems from Today's contest in Asyut Hack Club :)
Edit:
standard problem with this trick ABC 425E
There was a bug in my code (It's fixed now), Thanks Baraa-Ahmed for fixing the bug







