Modular Arithmetic for DSA
The habits that keep big numbers inside a long — reduce as you go, fixing negative remainders — plus the clean-thinking tricks (parity, jump to the next multiple, div & mod as a pair, circular indexing) and, when a problem asks for it, binary exponentiation and the modular inverse.
Assumes you know
After this you should be able to
- Keep modular calculations overflow-safe
- Use fast exponentiation and modular inverses
DSA Study Reference · Java
Five habits that keep giant numbers inside a long the whole way through — why
problems ask for mod 109+7, reducing as you go, binary exponentiation, modular inverse via
Fermat, and the overflow-safe tricks that keep your thinking clean.
What's inside#
- 1 · Quick Reference
- 2 · Detailed Walkthrough
- Mod: what & why
- int vs long & the L suffix
- Why 109+7 & the "sweet spot"
- Rule 1 · Use long everywhere
- Rule 2 · Take two at a time
- Rule 3 · Never use Math.pow()
- Rule 4 · Don't divide, take the inverse
- Rule 5 · Fix negatives when printing
- Clean-thinking tricks (/, %, parity)
- Worked Problem 1 · the big expression
- Worked Problem 2 · GP sum
- How to decide what to do
- Interview / Practice Q&A
- Key Takeaways
Quick Reference#
The whole page on one screen. Everything here is unpacked in full below. Watch for the marked lines: ★ trick · ⚠ pitfall · 💡 tip.
a % m= remainder after dividing a by m → range0 .. m-1- "answer mod M" asked → true answer is huge, they want the remainder
- Real enemy = overflow, not the big final number
int= 32-bit, max~2.1e9long= 64-bit, max~9.2e18- ⚠values that can grow → type
them
longfrom the start - literal:
1_000_000_007L(note theL)
- 1) prime → lets you divide (inverse exists), unique remainders
- 2) sweet spot:
M+M < int,M*M < long - 💡also 998244353 (for FFT/NTT) & 10^9+9
- R1 use
longeverywhere;mod = 1_000_000_007L - R2 take TWO at a time:
((a*b)%M * (c%M))%M - ⚠
a*b*coverflows before%ever runs - R3 never
Math.pow()(double!) → binary expo - R4 don't divide → multiply by inverse
- R5 print:
((ans % M) + M) % Mkills negatives - 💡Java shortcut:
Math.floorMod(a, M)
(a+b)%M = (a%M + b%M)%M(a-b)%M = (a%M - b%M + M)%M(a*b)%M = (a%M * b%M)%M- ⚠DIVISION does NOT distribute → inverse
- b even → square:
(a^(b/2))^2 - b odd → peel one:
a * a^(b-1) - base b=0 → return 1
- doodle: b in binary, each bit doubles the base; set bits get multiplied in
- FLT:
a^(M-1) % M = 1→a * a^(M-2) = 1 - ★
inv(a) = binpow(a, M-2)← a^-1 (a/b)%M = a * inv(b) % M- use for nCr, probabilities, avg, any "/" under mod
- ⚠needs M prime; else Extended Euclid
- sum 1..n =
n(n+1)/2; halve the EVEN one first - steps to next multiple of k:
(k - x%k) % k - ceil divide (no floats):
(x + k - 1) / k - ⚠never
Math.ceil((double)x/k)for big longs
Detailed Walkthrough#
The trap. Your logic is right and the small cases pass, but on a big
case the answer comes out negative — garbage where you expected trillions. Nothing in the logic
is wrong. The true answer had hundreds of digits, a long holds ~19, and
it silently wrapped around. That's why the problem says "print the answer modulo 109+7":
it hands you the one tool that keeps every intermediate value inside the box. The five habits below are the
whole survival kit — each is just a way to reduce early and never let a value grow too large.
long, reduce with
% after every step, and the /-and-% reading tricks (parity, next
multiple, circular index). Binary exponentiation and the modular inverse only appear when a problem
explicitly asks for "answer mod a prime" — build the reflexes first, and reach for those two
when a problem demands them.
1. What "mod" actually is, and why problems ask for it#
The modulo of a number is simply the remainder left over after division.
17 % 5 = 2, because 17 = 3×5 + 2.
The clock analogy. A 12-hour clock is arithmetic mod 12. It's 10 o'clock, you add 5 hours
— not 15 o'clock, it's 3. The clock silently did 15 % 12 = 3. Every value on the face
lives in 0..11 no matter how much time you add. Modular arithmetic is exactly this: a number
line rolled into a circle of size m, where everything stays inside 0 .. m-1.
m positions on the circle. That's all mod does.
When a problem ends with "return the answer modulo 109+7," it's telling you the true count is astronomically large — think number of ways to arrange things, which explodes factorially. Nobody can store or check a 100-digit number, so everyone compares just the remainder mod a fixed prime. If your remainder matches theirs, your logic was right.
2. int vs long, and the L suffix#
Overflow is the whole game, so the first move is knowing exactly how much room each type gives you and typing
the wide one on purpose. Anything that could grow past a couple billion goes in a long from the
start — not an int you widen later.
| Type | Holds up to | Named limit |
|---|---|---|
int (32-bit) | ~2.1 × 109 (231−1) | Integer.MAX_VALUE = 2147483647 |
long (64-bit) | ~9.2 × 1018 (263−1) | Long.MAX_VALUE = 9223372036854775807 |
int. Writing long mod = 1000000007; is
fine (it fits), but 1000000007 * 1000000007 computes as int × int first, overflows,
then widens — giving garbage. Always suffix modulus and big literals with L:
long MOD = 1_000_000_007L;. The underscores are just readability (Java allows them in numeric
literals).
3. Why that exact number, and the "sweet spot"#
109+7 is often called a "sweet spot." Two properties earn it that name.
| Property | What it buys you |
|---|---|
| It's prime | Every non-zero value has a modular inverse (Fermat needs a prime), so you can divide. Remainders are also "spread out" — fewer accidental collisions. |
| Sweet spot for size | Any value stays < 109+7. Add two →
~2×109 (still near int range). Multiply two →
~1018, which fits comfortably in a long (max
9.2×1018). So (a%M)*(b%M) never overflows a
long. |
109+9 (a twin prime, handy for double hashing) and
998244353 (a prime of the form c·223+1, the standard modulus for
NTT/FFT problems). If a problem hands you a non-prime modulus — as in the GP sum below —
Fermat's inverse breaks and you need a different method.
When you hit a modulo problem, run these#
Rule 1Use long everywhere#
The first defense is to never touch a 32-bit int for values that could grow. Declare the modulus
and every running value as long from the start, so nothing has a chance to overflow before you
reduce it.
long MOD = 1_000_000_007L; // modulus as a long constant
long ans = 0, prod = 1; // running values are long, not intint and multiply, the multiply happens in
int space before assignment to a long. Read big inputs into
long, or cast the first operand: (long) a * b. Reading via
Long.parseLong(...) or new Scanner(System.in).nextLong() keeps you safe.
Rule 2Take two at a time#
Never combine three or more factors before reducing. Multiply two, take % M,
then bring in the next one.
Here's the danger: in (a * b * c) % M, the product a * b may already have
overflowed before the * c or the % M ever runs. The modulo can't rescue a
value that's already garbage. So fold in one factor at a time, reducing after each step.
M×M,
safely inside a long.// Rule 2 in Java: fold in one factor at a time
long temp = (a % MOD) * (b % MOD) % MOD; // two at a time
temp = temp * (c % MOD) % MOD; // then the thirdThe properties this rests on#
Mod distributes over +, −, and × — reducing early
only discards whole multiples of M, which never affect a remainder. That's why "two at a
time" is legal.
(a − b) % M = (a%M − b%M + M) % M
(a × b) % M = (a%M × b%M) % M
(a ÷ b) % M ≠ (a%M) ÷ (b%M) ← division is special (Rule 4)
Rule 3Never use Math.pow() — binary
exponentiation#
Math.pow() returns a double, which can't hold a large integer exactly and gives you
no way to reduce mod M partway through. So (long) Math.pow(a, b) % MOD silently
returns wrong answers for large exponents — rounding error, plus the value overflows before the modulo
ever runs. The fix is to write the power yourself.
Math.pow(10, 18) is a double and can't represent that integer exactly. And you
can't reduce mod M during a Math.pow call, so the intermediate value
overflows anyway. For modular powers, always write your own integer routine.
The naive fix is a loop — multiply a into the answer b times, reducing
each step. That's O(b), too slow when b is up to 109.
// O(b) - correct but too slow for large b
long ans = 1;
for (int i = 0; i < b; i++) ans = ans * a % MOD;Binary exponentiation computes ab % M in
O(log b) by squaring the base and halving the exponent — because
ab = (ab/2)2 when b is even, and you peel off one
factor when b is odd.
Recursive version#
The recursive form reads exactly like the math: base case b == 0 returns 1, an odd b
peels off one factor, an even b squares the half.
static long MOD = 1_000_000_007L;
static long binpow(long a, long b) {
if (b == 0) return 1; // base case
if ((b & 1) == 1) // b is odd
return a % MOD * binpow(a, b - 1) % MOD;
long temp = binpow(a, b / 2); // b is even
return temp * temp % MOD;
}Iterative version (preferred in Java — no stack risk)#
b up to 109 the odd-branch adds a
call per bit and Java's default stack is shallower than you might expect. The iterative form is the same
O(log b) with zero recursion — the version to memorize for contests.
static long power(long a, long b) {
a %= MOD;
long res = 1;
while (b > 0) {
if ((b & 1) == 1) res = res * a % MOD; // bit set → multiply in
a = a * a % MOD; // square the base
b >>= 1; // next bit
}
return res;
}BigInteger.modPow(exp, mod), which does exactly this without overflow worries:
BigInteger.valueOf(a).modPow(BigInteger.valueOf(b), BigInteger.valueOf(MOD)).longValue(). It's
slower (object overhead) but bulletproof — good for a quick correct baseline or when you're unsure
about overflow. In hot loops, prefer your own long routine.
Rule 4In modulo you don't divide — you take the inverse #
Plain division breaks under a modulus: (12 / 6) % 10 = 2, but reducing first gives
(12%10) / (6%10) = 2/6, which isn't even an integer. Remainders throw away the information
division needs.
To divide by b under a modulus, multiply by b's modular
inverse — the number that plays the role of 1/b, i.e. the x with
(b · x) % M = 1.
A concrete example: find x so that (6 · x) % 7 = 1. Testing,
6 · 6 = 36, and 36 % 7 = 1 — so 6-1 = 6 under
mod 7. Dividing by 6 becomes multiplying by 6. But guessing doesn't scale, which is where Fermat comes in.
Fermat's Little Theorem: a(M−1) % M = 1 (M prime, gcd(a,M)=1)
⇒ a × a(M−2) % M = 1 ⇒ b-1 = b(M−2) % M
The key formula is exactly this last step: the inverse of any a is
aM-2, which you already know how to compute fast with binary exponentiation. So
inv is a one-liner on top of power.
// modular inverse via Fermat (MOD must be prime)
static long inv(long x) {
return power(x, MOD - 2); // x^(M-2) % M == x^-1
}
// then: (a / b) % M becomes a * inv(b) % MODM prime and gcd(b, M) = 1 (so b is
not a multiple of M, and never 0). If the modulus is composite — the GP
problem's Case 2 — use the Extended Euclidean algorithm instead, which finds the inverse whenever
gcd(b, M) = 1. There's no 1/0 in any world, so a zero denominator has no inverse.
nCr = n! / (r!(n-r)!), probabilities
and expected values, averages, or a problem that literally asks for
P · Q-1 mod M (that's Worked Problem 1). Precompute factorials and their
inverses once and every nCr is an O(1) lookup.
Rule 5Fix negatives when printing#
The % operator can return a negative result when the left side is negative:
-3 % 7 gives -3, not the mathematically clean 4. A negative remainder
fails comparisons and corrupts later steps — and it's how a "correct" solution ends up printing a
negative final answer.
(b - c) % M where c > b), the
result can be negative. Always add M then take % M again:
((ans % M) + M) % M. The + M lifts it back positive; the final % M
trims it if it was already fine.
// Rule 5 - the guaranteed-positive print
System.out.println(((ans % MOD) + MOD) % MOD);Math.floorMod(a, m) always returns a result with
the sign of m — so for positive M it's always in [0, M).
Math.floorMod(-3, 7) returns 4. You can use it as a drop-in for the
((a % M) + M) % M dance. (There's also Math.floorDiv for matching floored
division.) Both are worth knowing: the manual form works anywhere, and floorMod is the clean
one-liner when you reach for it.
Small moves that keep the logic clean#
The n(n+1)/2 trap#
The sum 1 + 2 + ... + n = n(n+1)/2. The final answer fits fine, but the intermediate
product n * (n+1) can overflow before you divide by 2. For
n ≈ 3×109, n(n+1) already blows past a long.
n and n+1, exactly one is even. Divide
the even one by 2 before multiplying — same result, but the peak intermediate value is halved
(a full extra bit of headroom), and the division stays exact.
static long tri(long n) {
return (n % 2 == 0) ? (n / 2) * (n + 1) : n * ((n + 1) / 2);
}n(n+1)/2 % M and n is up to
1018, reduce n and n+1 mod M first —
but then you've lost which was even, and /2 is no longer plain division. Multiply by
inv(2) instead: n%M * ((n+1)%M) %M * inv(2) %M.
Reaching the next multiple of k#
x % k is how far past the last multiple of k you are, so
k - (x % k) is the gap to the next one. If x is already a multiple that gives
k (wrong — should be 0), so one outer % k fixes the edge case.
(k - x%k) % k, and it's 0
when x is on a tick.| Goal | Java expression | Note |
|---|---|---|
| Round down to a multiple of k | (x / k) * k | integer division floors |
| Round up to a multiple of k | ((x + k - 1) / k) * k | +k-1 forces round-up |
Ceiling division ⌈x/k⌉ | (x + k - 1) / k | "how many k-buckets hold x" |
| Steps up to next multiple | (k - x % k) % k | 0 if already a multiple |
Math.ceil((double) x / k) — a double can't exactly hold large
long values and will round wrong at boundaries (same reason as Rule 3's Math.pow
ban). The exact integer form (x + k - 1) / k is faster and correct for every input. Java also
has Math.ceilDiv(x, k) (JDK 18+) if you're on a recent version.
Divide and remainder, read as a pair#
The same two operators keep showing up as a clean way to think, not just to compute. For any
x and a block size k: x / k tells you which block you're in
and x % k tells you where inside it. Almost every "wrap it around", "which bucket",
"flatten a grid", or "peel a digit" question is just this one idea in disguise.
| You want | Expression | Why it reads cleanly |
|---|---|---|
Is x even / odd? | (x & 1) == 0 / (x & 1) == 1 | the last bit is the parity; faster and clearer than x % 2 |
Next index on a ring of size n | (i + 1) % n | from the last slot it wraps to 0 on its own — no if |
| Previous index on that ring | (i - 1 + n) % n | the + n keeps it positive before the wrap (same guard as Rule 5) |
Flatten grid cell (r, c) of width C | idx = r * C + c | walk a 2D grid with a single index |
Un-flatten idx back to (r, c) | r = idx / C, c = idx % C | division gives the row, remainder gives the column |
| Last digit / drop it | x % 10 / x /= 10 | peel digits right-to-left in a loop |
Which bucket of size k | x / k (offset x % k) | group values into fixed-size ranges |
% n. Stepping past the end lands back at
0 automatically — the reason circular-array code stays branch-free.% n handle the edges
Circular buffers, round-robin turns, "rotate an array by k", clock arithmetic — all of them collapse to
indexing under % n. Whenever you catch yourself writing if (i == n) i = 0;, replace
it with i = (i + 1) % n. Going the other way, guard the negative first:
(i - 1 + n) % n.
All 5 rules in one expression#
Compute
Ans = (A + ((B − C)D) / (E × 100) − F × G) % (109+7),
given 1 ≤ A..G ≤ 109. If the answer is a fraction P/Q, print
P · Q-1 % M.
This is the capstone — every rule fires at once. Read it as a pipeline of temp values, each
reduced immediately (Rule 2), powers via binary expo (Rule 3), the division as a multiply-by-inverse (Rule
4), and a final positive-print (Rule 5).
/(E×100) becomes
× inv(t2); the print applies Rule 5.import java.util.Scanner;
public class Main {
static long MOD = 1_000_000_007L;
static long power(long a, long b) {
a %= MOD; long res = 1;
while (b > 0) {
if ((b & 1) == 1) res = res * a % MOD;
a = a * a % MOD; b >>= 1;
}
return res;
}
static long inv(long x) { return power(x, MOD - 2); }
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
long a = sc.nextLong(), b = sc.nextLong(), c = sc.nextLong();
long d = sc.nextLong(), e = sc.nextLong();
long f = sc.nextLong(), g = sc.nextLong();
long t = ((b - c) % MOD + MOD) % MOD; // (B-C), guard negative
t = power(t, d); // (B-C)^D (Rule 3)
long t2 = (e % MOD) * 100 % MOD; // E*100 (Rule 2)
t = t * inv(t2) % MOD; // / (E*100) (Rule 4)
t2 = f % MOD * (g % MOD) % MOD; // F*G (Rule 2)
t = (a + t) % MOD; // + A
t = (t - t2) % MOD; // - F*G
System.out.println(((t % MOD) + MOD) % MOD); // Rule 5
}
}inv() for the division automatically produces
P · Q-1 % M — that is the value of an irreducible fraction
P/Q under the modulus. You never form the fraction explicitly; the inverse does it for you.
Geometric series sum, mod M#
Compute F(x, n, m) = (1 + x + x2 + ... + xn) % m, with
1 ≤ x, n, m ≤ 109.
Summing term-by-term is O(n) — too slow. Notice this is a geometric progression (GP) with
first term 1 and ratio x, so the closed form applies:
Now every rule shows up: the numerator's power needs binary expo (Rule 3), the −1 can go
negative (Rule 5), and the division by (x−1) is a multiply-by-inverse (Rule 4). Two edge
cases matter.
x−1 = 0, which has no inverse. But if
x=1 the series is just 1+1+...+1 = n+1 terms, so answer is (n+1) % m.
Handle it separately.(2) m not prime: Fermat's inverse is invalid, so you can't use
inv(x-1). Fall back to the
O(log n) divide-and-conquer recurrence below, which needs no inverse at all.
Case 1 — m is prime (Fermat inverse works)#
static long gpSumPrime(long x, long n, long m) {
MOD = m; // power/inv use MOD
if (x == 1) return (n + 1) % m; // edge case (1)
long num = ((power(x, n + 1) - 1) % m + m) % m; // x^(n+1) - 1, guarded
long den = ((x - 1) % m + m) % m; // x - 1, guarded
long ans = num * inv(den) % m; // / (x-1) via inverse
return ((ans % m) + m) % m; // Rule 5
}Case 2 — m is not prime#
When you can't invert, avoid division entirely. Split the series in halves. For an even count of terms,
S(k terms) = S(k/2) × (1 + xk/2); for odd, peel one term. This is
O(log n) and uses only + and ×, so any modulus (prime or not)
is fine.
// sum of 1 + x + ... + x^(cnt-1), i.e. cnt terms, mod m. No inverse needed.
static long gpTerms(long x, long cnt, long m) {
if (cnt == 0) return 0;
if (cnt == 1) return 1 % m;
if ((cnt & 1) == 0) { // even: pair up the halves
long half = gpTerms(x, cnt / 2, m);
long factor = (1 + powMod(x, cnt / 2, m)) % m;
return half * factor % m;
} else { // odd: last term + the rest
return (gpTerms(x, cnt - 1, m) + powMod(x, cnt - 1, m)) % m;
}
}
// call with cnt = n + 1 terms: gpTerms(x, n + 1, m)
// powMod is binary exponentiation taking an explicit modulus mpowMod(a, b, m) is just the iterative power from Rule 3 with the modulus
passed as a parameter instead of the global MOD — because in this problem m
comes from input and may differ from case to case.
How to decide what to do#
Open a problem and run this top to bottom — it's the 5 rules as a checklist.
Interview / Practice Q&A#
Click to reveal. Answers sized to read aloud.
Why do problems ask for the answer modulo 109+7 instead of the real number?
long.How do you keep a value from overflowing when it can exceed a couple billion?
long for the modulus and every running
value, and suffix big literals with L. Watch method boundaries — reading input as
int and multiplying does the math in int space before widening, so read into
long or cast the first operand with (long) a * b.What does "take two at a time" mean and why is it necessary?
a * b * c, the product a*b can overflow a long before
the % M ever runs, and mod can't fix an already-corrupted value. Folding one factor at a
time keeps every intermediate below M×M, safely inside a long.Why never use Math.pow() for modular powers in Java?
Math.pow returns a double, which can't exactly represent large
integers and gives no way to reduce mod M during the computation, so it overflows and rounds wrong.
Write binary exponentiation instead: square the base and halve the exponent for O(log b),
reducing mod M each step. For a bulletproof-but-slower option, BigInteger.modPow works too.
How do you divide under a modulus, and why can't you divide directly?
2/6 isn't an integer). When M
is prime, the inverse of b is b^(M-2) % M by Fermat's little theorem, computed with binary
exponentiation. So a / b becomes a * power(b, M-2) % M.Your answer prints as a negative number. What's the fix?
% operator returns a negative result when the left operand is negative
(-3 % 7 is -3). Wrap the final answer as ((ans % M) + M) % M to
force it into [0, M). Math.floorMod(ans, M) is a built-in one-liner that does
the same thing.Walk through the GP-sum problem. What breaks when x = 1 or m isn't prime?
(x^(n+1) - 1)/(x - 1) divides by x-1. If
x=1 that's division by zero, but the series is just n+1 ones, so return
(n+1) % m. If m isn't prime, Fermat's inverse is invalid, so avoid division
entirely with an O(log n) divide-and-conquer that pairs the halves using only
+ and ×.For the sum 1 to n, why halve the even factor before multiplying?
n and n+1 is even, so dividing that one by 2 first
keeps the arithmetic exact and roughly halves the peak intermediate value — avoiding overflow that
n*(n+1) would cause before the division. If the answer is needed mod a prime and n is
enormous, reduce first and multiply by inv(2) instead.Given x and k, how many steps until x is a multiple of k, and why the outer % k?
(k - x % k) % k. The inner x % k is how far past the
previous multiple you are, so k minus that is the gap to the next one. The outer
% k handles the case where x is already a multiple, returning 0 instead of k.Key Takeaways#
- Overflow is the enemy, not the big number. A Java
longcaps near9.2×1018; cross it and values wrap to garbage silently. - Rule 1 — use
longeverywhere. Type growing valueslongfrom the start and suffix big literals withL. - Rule 2 — take two at a time.
((a*b)%M * (c%M))%M; never let three factors multiply before reducing. - Rule 3 — never
Math.pow(). Use binary exponentiation,O(log b), reducing each step (orBigInteger.modPow). - Rule 4 — don't divide, invert.
a/b → a * b^(M-2) % Mwhen M is prime (Fermat). - Rule 5 — fix negatives on print.
((ans%M)+M)%M, or Java'sMath.floorMod(ans, M). - Edge cases bite:
x=1and non-prime moduli break the inverse — special-case them. - Clean-thinking tricks: halve the even factor in
n(n+1)/2; jump to the next multiple via(k - x%k)%k; ceil-divide with(x+k-1)/k, never floats; and read/and%as a pair —x/kis the block,x%kthe offset (circular index(i+1)%n, grid flattenr*C+c).
The through-line. Every rule here is one defense against the same enemy — a value growing past
what a long can hold before you reduce it. Reduce early, square instead of looping, invert
instead of dividing, and guard the sign on the way out. Once those become reflexes, modular problems stop
being about arithmetic and start being about logic.