Modular Arithmetic
Why problems ask for a remainder
When a problem says “print the answer modulo 1000000007”, it is telling you the true answer is astronomically large — often larger than any fixed-width integer can hold. Rather than asking for big-integer arithmetic, the problem asks for the remainder, which stays small.
That constant, 109+7, is prime and just under 230. Both properties matter: primality makes division possible, and the size means two values below it multiply to under 260, which fits in a long.
static final long MOD = 1_000_000_007L;
The rules that hold
Addition, subtraction, and multiplication all commute with taking the remainder. You can reduce at every step and the final answer is unchanged.
long add(long a, long b) { return (a + b) % MOD; }
long mul(long a, long b) { return (a * b) % MOD; }
Subtraction needs care because Java’s % can return a negative value.
long sub(long a, long b) { return ((a - b) % MOD + MOD) % MOD; }
Adding MOD before the second reduction forces the result non-negative. Skipping this produces a negative answer that looks almost right, which is a hard bug to spot.
Reduce as you go, never at the end
// WRONG — overflows long long before the modulo
long product = 1;
for (int i = 1; i <= n; i++) product *= i;
System.out.println(product % MOD);
// CORRECT — stays below MOD^2 at every step
long product = 1;
for (int i = 1; i <= n; i++) product = product * i % MOD;The invariant to maintain: every value you store is already less than MOD. Then any single multiplication is at most (MOD-1)^2 ≈ 10^18, which fits in a long with room to spare.
If the modulus were larger — say near 1018 — even one multiplication would overflow, and you would need Math.multiplyHigh or BigInteger. For 109+7 you are safe.
Fast exponentiation
Computing a^b mod m by multiplying b times is O(b), which is hopeless when b is 1018. Repeated squaring does it in O(log b).
The idea: a^b is (a^(b/2))^2 when b is even, and a · a^(b-1) when odd. Reading the exponent’s bits from the bottom turns that into a loop.
static long power(long base, long exp, long mod) {
long result = 1;
base %= mod;
while (exp > 0) {
if ((exp & 1) == 1) {
result = result * base % mod;
}
base = base * base % mod;
exp >>= 1;
}
return result;
}
Each iteration halves the exponent, so 1018 takes about 60 steps.
Details worth checking
base %= modat the start, in case the caller passes something larger.exp >>= 1on along— using>>>is also fine here since the exponent is non-negative.- If the exponent can be negative, the problem means a modular inverse, not a power.
power(a, 0, mod)returns 1, which is correct including whenais 0 by the usual convention. If a problem cares about 00, it will say so.
Division and modular inverses
You cannot divide directly under a modulus. (a / b) % m is not ((a % m) / (b % m)) % m — integer division discards information the remainder no longer carries.
Instead multiply by the modular inverse of b: the value b⁻¹ such that b · b⁻¹ ≡ 1 (mod m).
When m is prime and b is not a multiple of it, Fermat’s little theorem gives the inverse directly:
static long inverse(long b, long mod) {
return power(b, mod - 2, mod); // requires mod to be prime
}
static long divide(long a, long b, long mod) {
return a % mod * inverse(b, mod) % mod;
}
Each inverse costs O(log m). If you need many inverses of consecutive small numbers, precompute them in one linear pass rather than calling power repeatedly.
When Fermat does not apply
power(b, mod - 2, mod) is only valid when the modulus is prime. Contest problems almost always use a prime, but check.
For a composite modulus, use the extended Euclidean algorithm, which finds the inverse whenever b and m share no common factor. An inverse does not exist at all when gcd(b, m) > 1 — if a problem leads you there, the intended solution probably avoids division.
Factorials and binomial coefficients
Counting problems usually need “n choose k” modulo a prime. Precompute factorials and their inverses once, then each coefficient is O(1).
static final int MAXN = 1_000_001;
static long[] fact = new long[MAXN];
static long[] invFact = new long[MAXN];
static void precompute() {
fact[0] = 1;
for (int i = 1; i < MAXN; i++) {
fact[i] = fact[i - 1] * i % MOD;
}
// one inverse, then walk downwards
invFact[MAXN - 1] = power(fact[MAXN - 1], MOD - 2, MOD);
for (int i = MAXN - 1; i > 0; i--) {
invFact[i - 1] = invFact[i] * i % MOD;
}
}
static long choose(int n, int k) {
if (k < 0 || k > n) return 0;
return fact[n] * invFact[k] % MOD * invFact[n - k] % MOD;
}
Computing the largest inverse factorial once and stepping downward avoids calling power a million times — the whole precomputation is O(N + log MOD).
The if (k < 0 || k > n) return 0; guard matters. Many recurrences naturally produce out-of-range arguments, and returning 0 for them is both mathematically right and simpler than avoiding them.
Operations under a prime modulus
| Operation | Code | Cost |
|---|---|---|
| Add | (a + b) % MOD | O(1) |
| Subtract | ((a - b) % MOD + MOD) % MOD | O(1) |
| Multiply | a * b % MOD | O(1) |
| Power | power(a, b, MOD) | O(log b) |
| Inverse | power(b, MOD - 2, MOD) | O(log MOD) |
| Divide | a * inverse(b) % MOD | O(log MOD) |
| Binomial | choose(n, k) after precompute | O(1) |
Common mistakes
- Negative results from subtraction. Always normalize.
- Reducing only at the end, after the value already overflowed.
- Dividing directly instead of multiplying by an inverse.
- Using Fermat with a composite modulus.
intinstead oflongfor intermediate products. Two values near 109 multiply to 1018.- Forgetting that the answer itself must be reduced before printing.
Practice
All answers modulo 10^9+7.
- Compute
n!for n up to 106. - Compute
a^bforaandbup to 1018. - Compute “n choose k” for n up to 106, answering 105 queries.
- Count the distinct paths from the top-left to the bottom-right of an R × C grid moving only right or down.
- Given N, compute the sum of
2^iforifrom 0 to N, for N up to 1018.
Hints
- One loop, reducing each step.
- Fast exponentiation. Reduce
afirst, since it exceeds the modulus. - Precompute factorials and inverse factorials, then O(1) per query.
- The answer is “R+C-2 choose R-1” — every path makes the same number of moves, and you only choose which are downward.
- The closed form is
2^(N+1) - 1. Compute the power, subtract one, and normalize the subtraction.