Modular Arithmetic
Modular computation for handling large numbers
Modular Arithmetic
In Competitive Programming, problems often have very large answers, requiring results as “mod ” or other values.
Basic Modulo
Modulo operation finds the remainder after division.
means where
const int MOD = 1e9 + 7;
int mod(int x) {
return ((x % MOD) + MOD) % MOD;
}
⚠️ Important: In C++, modulo of negative numbers may give negative results. e.g.,
-7 % 5 = -2. Add MOD back to fix this.
Properties of Modular Arithmetic
Addition and Subtraction
long long addMod(long long a, long long b) {
return ((a % MOD) + (b % MOD)) % MOD;
}
long long subMod(long long a, long long b) {
return ((a % MOD) - (b % MOD) + MOD) % MOD;
}
Multiplication
long long mulMod(long long a, long long b) {
return ((a % MOD) * (b % MOD)) % MOD;
}
Division (Requires Modular Inverse)
Where is the modular inverse of
Modular Exponentiation
Efficient modular exponentiation.
Binary Exponentiation
Calculate in
long long power(long long base, long long exp, long long mod) {
long long result = 1;
base %= mod;
while (exp > 0) {
if (exp & 1) { // exp is odd
result = (result * base) % mod;
}
base = (base * base) % mod;
exp >>= 1; // exp /= 2
}
return result;
}
Principle
- If : result =
- If is even:
- If is odd:
Example:
Modular Inverse
is the number such that
Method 1: Fermat’s Little Theorem
If is prime:
long long modInverse(long long b, long long mod = MOD) {
return power(b, mod - 2, mod);
}
// Division a / b mod m
long long divMod(long long a, long long b) {
return mulMod(a, modInverse(b));
}
Method 2: Extended Euclidean Algorithm
Works for general where
long long extGcd(long long a, long long b, long long &x, long long &y) {
if (b == 0) {
x = 1; y = 0;
return a;
}
long long x1, y1;
long long g = extGcd(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return g;
}
long long modInverseExt(long long b, long long mod = MOD) {
long long x, y;
extGcd(b, mod, x, y);
return (x % mod + mod) % mod;
}
Method 3: Pre-compute Inverse from 1 to n
const int MAXN = 1e6 + 5;
long long inv[MAXN];
void precomputeInverse(int n) {
inv[1] = 1;
for (int i = 2; i <= n; i++) {
inv[i] = (MOD - (MOD / i) * inv[MOD % i] % MOD) % MOD;
}
}
Factorial and Combinations
Pre-compute Factorial
const int MAXN = 1e6 + 5;
long long fact[MAXN], invFact[MAXN];
void precompute() {
fact[0] = 1;
for (int i = 1; i < MAXN; i++) {
fact[i] = (fact[i-1] * i) % MOD;
}
invFact[MAXN-1] = modInverse(fact[MAXN-1]);
for (int i = MAXN-2; i >= 0; i--) {
invFact[i] = (invFact[i+1] * (i+1)) % MOD;
}
}
Binomial Coefficient (nCr)
long long nCr(int n, int r) {
if (r < 0 || r > n) return 0;
return (fact[n] * invFact[r] % MOD) * invFact[n-r] % MOD;
}
Lucas’ Theorem
For computing when is very large and is prime
Where and
long long lucas(long long n, long long r, long long p) {
if (r == 0) return 1;
return (lucas(n / p, r / p, p) * nCr(n % p, r % p)) % p;
}
Usage Examples
Problem: Find
int main() {
long long n = 1000000000;
cout << power(2, n, MOD) << endl;
return 0;
}
Problem: Find number of ways to choose r items from n items
int main() {
precompute();
int n = 100000, r = 50000;
cout << nCr(n, r) << endl;
return 0;
}
Problem: Find
int main() {
long long a = 10, b = 3;
long long result = divMod(a, b);
// result is the value such that (result * 3) % MOD == 10
cout << result << endl;
return 0;
}
Why ?
- It’s prime - Makes finding modular inverse easy
- Fits in 32-bit -
- Multiplication won’t overflow 64-bit -
Summary
| Operation | Formula | Code |
|---|---|---|
| Addition | (a + b) % MOD | |
| Subtraction | (a - b + MOD) % MOD | |
| Multiplication | (a * b) % MOD | |
| Exponentiation | power(a, n, MOD) | |
| Division | a * modInverse(b) % MOD | |
| Inverse | power(a, MOD-2, MOD) | |
| nCr | fact[n] * invFact[r] * invFact[n-r] |
💡 Tip: Pre-compute factorial and inverse factorial in advance if you need to calculate nCr multiple times.