Introduction

I put together these combinatorics notes while preparing for the Lanqiao Cup National Finals.

It started with ABC458 E. I realized that although I could derive the correct formula, I did not know how to evaluate it. I was unfamiliar with multiplicative inverses, Fermat’s little theorem, division in modular arithmetic, and several common combinatorial counting models. After working through that problem, I followed this thread with a systematic set of practice problems covering binomial-coefficient templates, a linear recurrence for inverses, derangements, the binomial theorem, the reflection principle, and Catalan numbers. (For my ABC458 E solution, see my other post: AtCoder ABC458-E Review: Separators, Nonempty Groups, and Vandermonde’s Convolution.)

This is not an encyclopedia of combinatorics. I will not develop Lucas’s theorem, the extended Euclidean algorithm, the Chinese remainder theorem, or more complicated inclusion–exclusion models. Its scope is clear: collect the combinatorics fundamentals that can turn into contest points.

I therefore focus on three questions:

  1. How should division in modular arithmetic actually be handled?
  2. How can common combinatorial counting models be translated quickly into formulas?
  3. Which implementation details most often cause mistakes with boundaries, modular operations, or intermediate overflow?

Modular Division and Multiplicative Inverses

In ordinary mathematics, division is a natural operation. For example:

ab \frac{a}{b}

In modular arithmetic, however, we cannot simply write:

1
(a / b) % MOD

Integer division truncates, and “divide by bb” modulo a number should mean “multiply by the multiplicative inverse of bb,” rather than ordinary division.

Definition of a Multiplicative Inverse

If there is an integer xx satisfying:

bx≡1(modMOD) bx \equiv 1 \pmod {MOD}

Note: ≡\equiv means “is congruent to,” which can be understood as equality modulo MODMOD. In other words, bxbx and 11 have the same remainder when divided by MODMOD. Equivalently, bx−1bx-1 is divisible by MODMOD.

then xx is called the multiplicative inverse of bb modulo MODMOD, written:

b−1 b^{-1}

Thus:

ab≡a⋅b−1(modMOD) \frac{a}{b}\equiv a\cdot b^{-1}\pmod {MOD}

In code:

1
ans = a * inv(b) % MOD;

Remember that 00 has no inverse, because no xx can satisfy:

0⋅x≡1(modMOD) 0\cdot x\equiv 1\pmod {MOD}

The left-hand side is always 00.

Finding Inverses with Fermat’s Little Theorem

If MODMOD is prime and aa is not a multiple of MODMOD, Fermat’s little theorem gives:

aMOD−1≡1(modMOD) a^{MOD-1}\equiv 1 \pmod {MOD}

Multiplying both sides by a−1a^{-1} gives:

aMOD−2≡a−1(modMOD) a^{MOD-2}\equiv a^{-1}\pmod {MOD}

Therefore, when MODMOD is prime and a≢0(modMOD)a \not\equiv 0 \pmod {MOD}:

a−1≡aMOD−2(modMOD) a^{-1}\equiv a^{MOD-2}\pmod {MOD}

In code, we usually take its least nonnegative remainder in [0,MOD−1][0,MOD-1]:

inv(a)=aMOD−2 mod MOD inv(a)=a^{MOD-2}\bmod MOD

The code is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
using ll = long long;

//快速幂模板
ll qpow(ll a, ll b) {
ll res = 1;
a %= MOD;
while (b) {
if (b & 1) {
res = res * a % MOD;
}
a = a * a % MOD;
b >>= 1;
}
return res;
}

//费马小定理求逆元
ll inv(ll a) {
return qpow(a, MOD - 2);
}

The two comments in this template label binary exponentiation and inverse calculation using Fermat’s little theorem, respectively.

Common prime moduli include 1000000007 and 998244353.

Some problems also specify other particular prime moduli.

Conditions for Use

The conditions for using Fermat’s little theorem to find inverses are:

  1. MODMOD is prime;
  2. The value aa whose inverse is needed is coprime to MODMOD;
  3. Under a prime modulus, a≢0(modMOD)a\not\equiv 0\pmod {MOD} guarantees that an inverse exists.

If the modulus is not prime, or aa is not coprime to it, we cannot blindly use:

1
qpow(a, MOD - 2)

That is a more general inverse problem, usually requiring tools such as the extended Euclidean algorithm. I will not cover it here.


A Linear Recurrence for Inverses of Individual Integers

If we need the inverse of every integer in 1∼n1\sim n, we can of course write this for each ii:

1
inv[i] = qpow(i, MOD - 2);

But the complexity is:

O(nlog⁡MOD) O(n\log MOD)

For large nn, such as 3×1063\times 10^6, that is less efficient than we would like.

With a prime modulus, a linear recurrence can find all the inverses of individual integers in O(n)O(n) time.

The recurrence starts with:

inv1=1 inv_1 = 1

For i≥2i\ge 2:

invi≡(MOD−⌊MODi⌋)⋅invMOD mod i(modMOD) inv_i \equiv \left(MOD-\left\lfloor\frac{MOD}{i}\right\rfloor\right)\cdot inv_{MOD\bmod i}\pmod{MOD}

Here, inviinv_i denotes the multiplicative inverse of ii modulo MODMOD.

The point of this section is to understand where the formula comes from.

Why inv[0] Does Not Need Initialization

The meaning of an individual inverse inv[i] is:

i⋅inv[i]≡1(modMOD) i\cdot inv[i]\equiv 1\pmod {MOD}

When i=0i=0, this becomes:

0⋅inv[0]≡1(modMOD) 0\cdot inv[0]\equiv 1\pmod {MOD}

This is clearly impossible, so 00 has no inverse.

The first meaningful entry in the array is therefore:

1
inv[1] = 1;

because:

1⋅1≡1(modMOD) 1\cdot 1\equiv 1\pmod {MOD}

Deriving the Recurrence

Suppose we want the inverse of ii. Integer division gives:

MOD=⌊MODi⌋⋅i+MOD mod i MOD=\left\lfloor \frac{MOD}{i}\right\rfloor\cdot i+MOD\bmod i

For convenience, write:

q=⌊MODi⌋ q=\left\lfloor \frac{MOD}{i}\right\rfloor r=MOD mod i r=MOD\bmod i

Then:

MOD=qi+r MOD=qi+r

Modulo MODMOD, we have MOD≡0MOD\equiv 0, so:

qi+r≡0(modMOD) qi+r\equiv 0\pmod {MOD}

Rearranging:

r≡−qi(modMOD) r\equiv -qi\pmod {MOD}

That is:

MOD mod i≡−⌊MODi⌋i(modMOD) MOD\bmod i\equiv -\left\lfloor \frac{MOD}{i}\right\rfloor i\pmod {MOD}

Next, multiply both sides by the inverse of rr, namely inv[r]inv[r].

Since:

r⋅inv[r]≡1(modMOD) r\cdot inv[r]\equiv 1\pmod {MOD}

we have:

(−qi)⋅inv[r]≡1(modMOD) (-qi)\cdot inv[r]\equiv 1\pmod {MOD}

Rearranging gives:

i⋅(−q⋅inv[r])≡1(modMOD) i\cdot (-q\cdot inv[r])\equiv 1\pmod {MOD}

This shows that:

−q⋅inv[r] -q\cdot inv[r]

is the inverse of ii.

Substitute back for qq and rr:

inv[i]≡−⌊MODi⌋⋅inv[MOD mod i](modMOD) inv[i]\equiv -\left\lfloor \frac{MOD}{i}\right\rfloor\cdot inv[MOD\bmod i]\pmod {MOD}

To avoid a negative value, write:

inv[i]=(MOD−⌊MODi⌋)⋅inv[MOD mod i] mod MOD inv[i]=\left(MOD-\left\lfloor \frac{MOD}{i}\right\rfloor\right)\cdot inv[MOD\bmod i]\bmod MOD

This is the formula in the code:

1
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;

Why We Can Compute in Increasing Order

Since:

MOD mod i<i MOD\bmod i<i

computing inv[i] uses inv[MOD % i], whose index is always smaller than ii.

Starting from inv[1] and proceeding forward therefore ensures that every required value has already been computed.

Here is the handwritten derivation:

Handwritten derivation of the linear recurrence for individual inverses

Image legend: PP denotes the modulus, kk the integer quotient, and rr the remainder. 左右%P means “reduce both sides modulo PP”; 左移r means “move rr to the left”; 左右同乘 means “multiply both sides by the same expression”; 查表 means “look up the precomputed value.” The bottom line is the resulting recurrence for inv[i].

Template

1
2
3
4
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}

This linear recurrence computes inverses of individual integers:

inv[i]=i−1 inv[i]=i^{-1}

Do not confuse them with inverse factorials.


Precomputing Factorials and a Binomial-Coefficient Template

The binomial-coefficient formula is:

Cnk=n!k!(n−k)! C_{n}^{k}=\frac{n!}{k!(n-k)!}

In modular arithmetic, division becomes multiplication by inverses, so:

Cnk≡n!⋅(k!)−1⋅((n−k)!)−1(modMOD) C_{n}^{k}\equiv n!\cdot (k!)^{-1}\cdot ((n-k)!)^{-1}\pmod {MOD}

We can therefore precompute:

1
2
fac[i]  = i!
ifac[i] = (i!)^{-1}

and then evaluate binomial coefficients quickly.

The Factorial Array

The factorial array is straightforward:

1
2
3
4
fac[0] = 1;
for (int i = 1; i <= N; ++i) {
fac[i] = fac[i - 1] * i % MOD;
}

Here:

fac[i]=i! fac[i]=i!

The Inverse-Factorial Array

The inverse-factorial array represents:

ifac[i]=(i!)−1 ifac[i]=(i!)^{-1}

First compute the largest entry:

1
ifac[N] = qpow(fac[N], MOD - 2);

Notice that this uses:

1
qpow(fac[N], MOD - 2)

rather than:

1
qpow(N, MOD - 2)

because ifac[N] represents (N!)−1(N!)^{-1}, not N−1N^{-1}.

Then work backward.

Since:

(i+1)!=i!⋅(i+1) (i+1)! = i!\cdot (i+1)

we have:

((i+1)!)−1⋅(i+1)=(i!)−1 ((i+1)!)^{-1}\cdot (i+1) = (i!)^{-1}

That is:

ifac[i]=ifac[i+1]⋅(i+1) ifac[i]=ifac[i+1]\cdot (i+1)

In code:

1
2
3
for (int i = N - 1; i >= 0; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % MOD;
}

Binomial-Coefficient Template

1
2
3
4
5
6
ll C(int n, int k) {
if (k < 0 || k > n) {
return 0;
}
return fac[n] * ifac[k] % MOD * ifac[n - k] % MOD;
}

The complete preprocessing template is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
long long qpow(long long a, long long b) {
long long res = 1;
a %= MOD;
while (b) {
if (b & 1) res = res * a % MOD;
a = a * a % MOD;
b >>= 1;
}
return res;
}

void init(int N) {
fac[0] = 1;
for (int i = 1; i <= N; ++i) {
fac[i] = fac[i - 1] * i % MOD;
}
ifac[N] = qpow(fac[N], MOD - 2);
for (int i = N - 1; i >= 0; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % MOD;
}
}

long long C(int n, int k) {
if (k < 0 || k > n) return 0;
return fac[n] * ifac[k] % MOD * ifac[n - k] % MOD;
}

Limits of Applicability

This template applies when:

  1. MODMOD is prime;
  2. The largest precomputed NN is not too large;
  3. The ordinary factorials do not encounter the more complicated case n≥MODn\ge MOD.

If nn is enormous, or factorials contain a factor of the modulus once n≥MODn\ge MOD, this template cannot simply be applied as is. Those are more general topics involving tools such as Lucas’s theorem, which I will not cover here.


The Derangement Model

A derangement asks: given nn elements, how many permutations place no element back in its original position?

Denote the number of derangements by:

Dn D_n

The usual initial values are:

D0=1,D1=0 D_0=1, D_1=0

The recurrence is:

Dn=(n−1)(Dn−1+Dn−2) D_n=(n-1)(D_{n-1}+D_{n-2})

Deriving the Recurrence

Consider the nnth element.

It cannot occupy its own position, so it can occupy any of the first n−1n-1 positions. Suppose we place it at position kk, where:

1≤k≤n−1 1\le k\le n-1

Next, consider the element originally belonging to position kk.

Call the kkth element kk.

After placing nn at position kk, there are two cases for element kk.

Case 1: Element k Goes to Position n

In other words, kk and nn exchange positions.

The positions of these two elements are now fixed:

  • nn occupies kk's position;
  • kk occupies nn's position.

The remaining n−2n-2 elements must still all be deranged, giving:

Dn−2 D_{n-2}

Case 2: Element k Does Not Go to Position n

We can now regard position nn as the forbidden position corresponding to kk.

In other words, after removing element nn, the remaining n−1n-1 elements still form a derangement problem: each element must avoid its corresponding forbidden position.

This contributes:

Dn−1 D_{n-1}

The nnth element has n−1n-1 possible positions, so the total is:

Dn=(n−1)(Dn−1+Dn−2) D_n=(n-1)(D_{n-1}+D_{n-2})

Template

1
2
3
4
5
D[0] = 1;
D[1] = 0;
for (int i = 2; i <= N; ++i) {
D[i] = (i - 1) * (D[i - 1] + D[i - 2]) % MOD;
}

If the problem does not require a modulus and the bounds are small, % MOD can be omitted.

Combining Derangements with Binomial Coefficients

A common variant asks for permutations with exactly mm fixed positions.

First choose those mm fixed positions:

Cnm C_{n}^{m}

None of the remaining n−mn-m positions may be fixed, so they form a derangement problem:

Dn−m D_{n-m}

The answer is therefore:

Cnm⋅Dn−m C_{n}^{m}\cdot D_{n-m}

Luogu P4071 is a typical application of this model.


The Binomial Theorem and Coefficient Problems

The basic form of the binomial theorem is:

(A+B)k=∑i=0kCkiAiBk−i (A+B)^k=\sum_{i=0}^{k}C_{k}^{i}A^iB^{k-i}

One way to understand it is:

There are kk factors, and we choose either AA or BB from each. Choosing AA exactly ii times means choosing BB exactly k−ik-i times. There are CkiC_{k}^{i} such choices.

Binomials with Coefficients

Suppose the expression is:

(by+ax)k (by+ax)^k

and we want the coefficient of the term:

xnym x^n y^m

To obtain xnx^n, we must choose axax exactly nn times; to obtain ymy^m, we must choose byby exactly mm times. The problem usually guarantees:

n+m=k n+m=k

Choosing which nn of the kk factors supply axax gives:

Ckn C_{k}^{n}

Each choice of axax contributes one factor of aa, so nn such choices contribute:

an a^n

Each choice of byby contributes one factor of bb, so mm such choices contribute:

bm b^m

The final coefficient is therefore:

Cknanbm C_{k}^{n}a^n b^m

Equivalently:

Ckmanbm C_{k}^{m}a^n b^m

since n+m=kn+m=k.

In Code

1
ans = C(k, n) * qpow(a, n) % MOD * qpow(b, m) % MOD;

Two easy mistakes are calculating only the binomial coefficient and using CnmC_{n}^{m} as the binomial coefficient.

The key to Luogu P1313 is translating the polynomial-coefficient question in the statement into this formula.


The Reflection Principle and Generalized Catalan Counting

The reflection principle is a classic way to handle constraints requiring every prefix to remain valid.

A common model is:

Given nn copies of 1 and mm copies of 0, count the strings in which every prefix contains at least as many 1s as 0s.

That is, every prefix must satisfy:

#1≥#0 \#1\ge \#0

Total Number of Strings

Ignoring the prefix constraint, choose mm of the n+mn+m positions for 0, and fill the rest with 1.

The total number of strings is therefore:

Cn+mm C_{n+m}^{m}

Characterizing Invalid Strings

An invalid string has some prefix satisfying:

#0>#1 \#0>\#1

Scan an invalid string from left to right and consider the first position where it becomes invalid.

At that position, we must have:

#0=#1+1 \#0=\#1+1

Only one character is added at a time, so the difference cannot jump over this state.

Reflecting the First Prefix That Crosses the Boundary

For an invalid string, find the first prefix satisfying:

#0=#1+1 \#0=\#1+1

Swap every 0 and 1 in that prefix.

Suppose the prefix originally contains aa copies of 1 and a+1a+1 copies of 0:

a 个 1,a+1 个 0 a\text{ 个 }1, \quad a+1\text{ 个 }0

After reflection, it contains a+1a+1 copies of 1 and aa copies of 0:

a+1 个 1,a 个 0 a+1\text{ 个 }1, \quad a\text{ 个 }0

The totals in the whole string therefore change from nn copies of 1 and mm copies of 0:

n 个 1,m 个 0 n\text{ 个 }1, \quad m\text{ 个 }0

to n+1n+1 copies of 1 and m−1m-1 copies of 0:

n+1 个 1,m−1 个 0 n+1\text{ 个 }1, \quad m-1\text{ 个 }0

Thus, every invalid string maps to an unrestricted string containing n+1n+1 copies of 1 and m−1m-1 copies of 0.

Why This Is a Bijection

Proving a mapping in one direction is not enough; we must also show that it neither overcounts nor misses anything.

Conversely, take any string containing n+1n+1 copies of 1 and m−1m-1 copies of 0:

n+1 个 1,m−1 个 0 n+1\text{ 个 }1, \quad m-1\text{ 个 }0

Scan it from left to right and find the first prefix satisfying:

#1=#0+1 \#1=\#0+1

This prefix must exist: the whole string has one more 1 and one fewer 0 than before. In terms of the prefix difference, the final difference must become positive, so it must reach +1+1 for the first time somewhere.

Then swap every 0 and 1 in this prefix.

The prefix originally contains a+1a+1 copies of 1 and aa copies of 0:

a+1 个 1,a 个 0 a+1\text{ 个 }1, \quad a\text{ 个 }0

After reflection, it contains aa copies of 1 and a+1a+1 copies of 0:

a 个 1,a+1 个 0 a\text{ 个 }1, \quad a+1\text{ 个 }0

The reflected string therefore first reaches:

#0=#1+1 \#0=\#1+1

at this prefix, making it an invalid string.

The operations in the two directions are inverses:

  • Reflect an invalid string at the first point where its difference falls to −1-1, obtaining a string of the other, unrestricted kind;
  • Reflect that unrestricted string at the first point where its difference rises to +1+1, returning to the invalid string.

The number of invalid strings is therefore:

Cn+mm−1 C_{n+m}^{m-1}

The Generalized Formula

The number of valid strings is thus:

Cn+mm−Cn+mm−1 C_{n+m}^{m}-C_{n+m}^{m-1}

If n<mn<m, even the entire string has fewer 1s than 0s, so every prefix cannot possibly have at least as many 1s as 0s. The answer is directly 00.

Luogu P1641 is a typical problem using this model.


Standard Catalan Numbers and Pitfalls Without a Modulus

Setting n=mn=m in the previous section gives the standard Catalan-number model.

That is:

Given nn copies of 1 and nn copies of 0, require every prefix to contain at least as many 1s as 0s.

The reflection-principle formula gives:

Catn=C2nn−C2nn−1 Cat_n=C_{2n}^{n}-C_{2n}^{n-1}

This is one form of the nnth Catalan number.

It also simplifies to:

Catn=1n+1C2nn Cat_n=\frac{1}{n+1}C_{2n}^{n}

Here is a short derivation. Since:

C2nn=(2n)!n! n! C_{2n}^{n}=\frac{(2n)!}{n!\,n!}

and:

C2nn−1=(2n)!(n−1)!(n+1)! C_{2n}^{n-1}=\frac{(2n)!}{(n-1)!(n+1)!}

the ratio is:

C2nn−1C2nn=n! n!(n−1)!(n+1)!=nn+1 \frac{C_{2n}^{n-1}}{C_{2n}^{n}} = \frac{n!\,n!}{(n-1)!(n+1)!} = \frac{n}{n+1}

In other words:

C2nn−1=nn+1C2nn C_{2n}^{n-1}=\frac{n}{n+1}C_{2n}^{n}

Substitute back into the original expression:

Catn=C2nn−C2nn−1 Cat_n=C_{2n}^{n}-C_{2n}^{n-1}

to obtain:

Catn=C2nn−nn+1C2nn=1n+1C2nn Cat_n = C_{2n}^{n}-\frac{n}{n+1}C_{2n}^{n} = \frac{1}{n+1}C_{2n}^{n}

From the Binomial-Coefficient Formula to a Recurrence

If there is no modulus and nn is small, we can compute Catalan numbers directly with a linear recurrence, avoiding intermediate factorial overflow.

Starting from:

Catn=1n+1C2nn Cat_n=\frac{1}{n+1}C_{2n}^{n}

and:

Catn−1=1nC2n−2n−1 Cat_{n-1}=\frac{1}{n}C_{2n-2}^{n-1}

consider their ratio:

CatnCatn−1=1n+1C2nn1nC2n−2n−1 \frac{Cat_n}{Cat_{n-1}} = \frac{\frac{1}{n+1}C_{2n}^{n}}{\frac{1}{n}C_{2n-2}^{n-1}}

Rearranging gives:

CatnCatn−1=nn+1⋅C2nnC2n−2n−1 \frac{Cat_n}{Cat_{n-1}} = \frac{n}{n+1}\cdot \frac{C_{2n}^{n}}{C_{2n-2}^{n-1}}

where:

C2nnC2n−2n−1=(2n)(2n−1)n2 \frac{C_{2n}^{n}}{C_{2n-2}^{n-1}} = \frac{(2n)(2n-1)}{n^2}

Thus:

CatnCatn−1=nn+1⋅(2n)(2n−1)n2 \frac{Cat_n}{Cat_{n-1}} = \frac{n}{n+1}\cdot \frac{(2n)(2n-1)}{n^2}

After simplification:

CatnCatn−1=4n−2n+1 \frac{Cat_n}{Cat_{n-1}}=\frac{4n-2}{n+1}

The recurrence is therefore:

Catn=Catn−1⋅4n−2n+1 Cat_n=Cat_{n-1}\cdot \frac{4n-2}{n+1}

In code:

1
2
3
4
cat[0] = 1;
for (int i = 1; i <= n; ++i) {
cat[i] = cat[i - 1] * (4 * i - 2) / (i + 1);
}

Here is the handwritten derivation:

Handwritten derivation of the linear recurrence for standard Catalan numbers

Image guide: the top section compares the two binomial coefficients, the middle obtains the standard Catalan formula, and the bottom takes the ratio of consecutive Catalan numbers to derive the recurrence. The notation matches the formulas above.

The Pitfall When Computing Without a Modulus

In Luogu P1754, n≤20n\le 20, and the final answer fits in long long.

But directly using factorials to calculate:

C2nn−C2nn−1 C_{2n}^{n}-C_{2n}^{n-1}

requires computing up to:

(2n)! (2n)!

When n=20n=20, an intermediate value is:

40! 40!

This is far beyond the range of long long.

The pitfall here is therefore about intermediate values rather than the final answer:

A final answer that fits does not guarantee that intermediate factorials fit.

In this situation, use the Catalan recurrence, a more reliable multiplicative formula for binomial coefficients, or arbitrary-precision arithmetic.


Common Pitfalls

This section collects the places in this topic where it is easiest to make a coding or reasoning mistake.

Distinguish Individual Inverses, Inverse Factorials, and Factorials

The three arrays most easily confused are:

1
2
3
fac[i]  = i!
ifac[i] = (i!)^{-1}
inv[i] = i^{-1}

Their meanings are entirely different.

fac[i] is a factorial:

fac[i]=i! fac[i]=i!

ifac[i] is the inverse of a factorial:

ifac[i]=(i!)−1 ifac[i]=(i!)^{-1}

inv[i] is the inverse of the individual integer ii:

inv[i]=i−1 inv[i]=i^{-1}

The binomial-coefficient template uses:

1
fac[n] * ifac[k] % MOD * ifac[n - k] % MOD

Ordinary modular division uses:

1
a * inv[b] % MOD

Do Not Confuse Forward inv with Backward ifac

The linear recurrence for individual inverses proceeds forward:

1
2
3
4
inv[1] = 1;
for (int i = 2; i <= n; ++i) {
inv[i] = (MOD - MOD / i) * inv[MOD % i] % MOD;
}

It computes:

inv[i]=i−1 inv[i]=i^{-1}

The inverse-factorial recurrence proceeds backward:

1
2
3
4
ifac[N] = qpow(fac[N], MOD - 2);
for (int i = N - 1; i >= 0; --i) {
ifac[i] = ifac[i + 1] * (i + 1) % MOD;
}

It computes:

ifac[i]=(i!)−1 ifac[i]=(i!)^{-1}

Both formulas involve inverses, but they calculate fundamentally different things.

Add MOD for Modular Subtraction

If the answer contains a subtraction, such as:

a−b a-b

write it modulo the modulus as:

1
(a - b + MOD) % MOD

Otherwise, even when the actual answer is nonnegative, the first reduced value may be smaller than the second, causing a negative output.

In Luogu P1641, the formula is:

Cn+mm−Cn+mm−1 C_{n+m}^{m}-C_{n+m}^{m-1}

Subtracting directly can produce WA.

0 Has No Inverse

No xx satisfies:

0⋅x≡1(modMOD) 0\cdot x\equiv 1\pmod {MOD}

so inv[0] has no meaning.

When finding individual inverses with a linear recurrence, start at inv[1].

Inverses via Fermat Require a Prime Modulus

1
qpow(a, MOD - 2)

This expression relies on Fermat’s little theorem, so MODMOD must be prime and aa must not be a multiple of MODMOD.

For a nonprime modulus, we need more general methods for determining whether an inverse exists and computing it. Those are beyond this article.

A Final Answer That Fits Does Not Guarantee Intermediate Factorials Fit

In combinatorial counting without a modulus, checking only the final answer’s range is insufficient.

For example, in Luogu P1754, the final answer fits in long long, but calculating binomial coefficients with factorials produces 40!40! as an intermediate value and immediately overflows.

Use a different calculation method in such cases, such as the Catalan recurrence.

Use the Correct Variables in Binomial Coefficients

It is especially easy to mix up variables in binomial-coefficient problems.

For example, Luogu P1313 asks for the coefficient of xnymx^n y^m in:

(by+ax)k (by+ax)^k

The correct binomial coefficient is:

Ckn C_{k}^{n}

rather than:

Cnm C_{n}^{m}

because we are choosing nn of the kk factors from which to take axax.

Precompute Through the Largest Index the Problem Needs

If the problem requires:

Cn+mn C_{n+m}^{n}

the preprocessing range must reach at least:

n+m n+m

Do not stop at only nn or mm.

For example, grid-path problems such as Luogu P2265 need:

Cn+mn C_{n+m}^{n}

Prefix-Validity Problems Have No Solution When n < m

Consider the model:

Given nn copies of 1 and mm copies of 0, require every prefix to contain at least as many 1s as 0s.

If:

n<m n<m

the whole string already contains fewer 1s than 0s. The condition is impossible, so the answer is directly 00.


Practice Log

These are the practice problems used in this topic. I do not expand their solutions here; I only note what each one trains and link to the accepted code.


Closing Thoughts

These notes collect the combinatorics fundamentals I filled in while preparing for the Lanqiao Cup.

Starting with modular division, multiplicative inverses answer how to divide modulo a number. Fermat’s little theorem and binary exponentiation provide the basic tools for finding inverses under a prime modulus. A linear recurrence extends this to finding individual inverses in bulk, while precomputed factorials and inverse factorials form the basis of the binomial-coefficient template.

At the modeling level, derangements, the binomial theorem, the reflection principle, and Catalan numbers each cover common kinds of combinatorial counting problems. What matters is remembering how a statement turns into these models, rather than remembering the code for one particular problem:

  • Fixed points and elements avoiding their original positions suggest derangements;
  • The coefficient of a specified term in a polynomial expansion suggests the binomial theorem;
  • Prefix-validity constraints in paths, parentheses, queues, and binary strings suggest the reflection principle;
  • Prefix-validity problems with equal counts lead to standard Catalan numbers.

This is far from all of combinatorics, but for contests such as the Lanqiao Cup, it already covers many basic models that can translate directly into points. If I encounter more general counting problems later, I can add Lucas’s theorem, the extended Euclidean algorithm, or more complicated inclusion–exclusion as needed. At this stage, getting these basic templates and derivations solid matters more than expanding the list blindly.