Permutations
Combinations
Also written .
Pascal’s identity:
Basis of Pascal’s triangle; gives an DP for binomial coefficients without factorials or modular inverses.
Identities:
Binomial Theorem
Computing nCr Fast, Modulo a Prime
For up to –: precompute factorials and inverse factorials mod , then answer each query in . (See Modular Arithmetic for the standalone modinv / modpow building blocks.)
Code — Factorial / Inverse-Factorial Precomputation
#include <bits/stdc++.h>
using namespace std;
static const long long MOD = 1000000007;
static const int MAXN = 1000000;
long long fact[MAXN + 1], invfact[MAXN + 1];
long long modpow(long long a, long long b, long long mod) {
long long res = 1;
a %= mod;
while (b > 0) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
void precompute() {
fact[0] = 1;
for (int i = 1; i <= MAXN; i++)
fact[i] = fact[i - 1] * i % MOD;
invfact[MAXN] = modpow(fact[MAXN], MOD - 2, MOD);
for (int i = MAXN; i > 0; i--)
invfact[i - 1] = invfact[i] * i % MOD;
}
long long nCr(int n, int r) {
if (r < 0 || r > n) return 0;
return fact[n] * invfact[r] % MOD * invfact[n - r] % MOD;
}Code — Pascal’s-Triangle DP (Small n, No Modular Inverse Needed)
vector<vector<long long>> pascal(int n, long long mod) {
vector<vector<long long>> C(n + 1, vector<long long>(n + 1, 0));
for (int i = 0; i <= n; i++) {
C[i][0] = 1;
for (int j = 1; j <= i; j++)
C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
}
return C;
}Catalan Numbers
Mathematical Proof
The closed form is derived with the reflection principle: count lattice paths from to using unit right/up steps that never cross above the diagonal. The total number of monotone paths is . Reflecting any “bad” path (one that touches the line ) across that line maps it bijectively onto an unconstrained path to , of which there are . Subtracting the bad paths leaves valid paths, which simplifies to .
Catalan numbers count balanced parenthesizations, binary trees with internal nodes, Dyck paths, and polygon triangulations, among many other structures.
long long catalan(int n, long long mod) {
// requires precompute() from the nCr section above
return ((nCr(2 * n, n) - nCr(2 * n, n + 1)) % mod + mod) % mod;
}Time Complexity: per query (given precomputed factorials), precompute
Stars and Bars
Number of ways to distribute identical items into distinguishable bins.
Empty bins allowed:
Each bin non-empty:
Mathematical Proof
Represent a distribution as a row of stars (items) separated by bars (bin boundaries). Any arrangement of these symbols is a valid distribution, and it’s fully determined by choosing which of the positions hold bars — hence . For the non-empty case, first place one item in every bin, then distribute the remaining items freely, giving .
long long distributeItems(int n, int k, bool allowEmpty) {
if (allowEmpty) return nCr(n + k - 1, k - 1);
return nCr(n - 1, k - 1); // n must be >= k
}Inclusion-Exclusion Principle
Standard applications: counting numbers divisible by at least one of a set of primes, counting surjective functions, Euler’s totient (see General), and derangements (below).
// counts integers in [1, N] divisible by at least one of the given primes
long long countDivisibleByAny(long long N, vector<long long> &primes) {
int k = primes.size();
long long total = 0;
for (int mask = 1; mask < (1 << k); mask++) {
long long lcm = 1;
int bits = __builtin_popcount(mask);
bool overflow = false;
for (int i = 0; i < k; i++) {
if (mask & (1 << i)) {
long long g = __gcd(lcm, primes[i]);
if (lcm / g > N / primes[i]) { overflow = true; break; }
lcm = lcm / g * primes[i];
}
}
if (overflow) continue;
long long term = N / lcm;
total += (bits % 2 == 1) ? term : -term;
}
return total;
}Time Complexity: for sets
Derangements
Permutations of elements with no fixed points.
Mathematical Proof
Applying Inclusion-Exclusion to the events ” is a fixed point” over all positions gives .
long long derangements(int n, long long mod) {
vector<long long> D(n + 1);
D[0] = 1;
if (n >= 1) D[1] = 0;
for (int i = 2; i <= n; i++)
D[i] = (i - 1) * ((D[i - 1] + D[i - 2]) % mod) % mod;
return D[n];
}Time Complexity:
Burnside’s Lemma
Counts the number of distinct objects up to the symmetry of a group acting on a set :
where is the set of elements of fixed by .
Classic example — necklaces: count distinct necklaces of beads and colors under rotation. A rotation by positions decomposes the beads into cycles, and a coloring is fixed by that rotation iff it’s constant on every cycle — giving fixed colorings.
long long distinctNecklaces(int n, int k, long long mod) {
long long total = 0;
for (int d = 0; d < n; d++) {
int g = __gcd(n, d);
total = (total + modpow(k, g, mod)) % mod;
}
return total * modinv(n, mod) % mod; // modinv from Modular Arithmetic
}Time Complexity:
Pólya Enumeration Theorem
A restatement of Burnside’s Lemma specialized to coloring problems: since a coloring is fixed by exactly when it’s constant on every cycle of , where is the number of cycles in ‘s permutation of the underlying positions. This gives
The necklace-counting code above is already an instance of PET: rotation by decomposes positions into cycles. PET becomes essential (over plain Burnside) once the group includes more complex symmetries (e.g. reflections, or automorphisms of a graph), where must be computed from the specific permutation structure of each rather than a simple .
Generating Functions
Ordinary Generating Function (OGF) of a sequence :
Sequence operations become algebraic operations on the generating function: shifting the sequence corresponds to multiplying by , and convolution () corresponds to multiplying the two generating functions, .
Examples:
Exponential Generating Function (EGF), used for labeled structures:
Example: the EGF for permutations of labeled items is ; the EGF for derangements is .
In competitive programming, generating functions are mainly wielded through polynomial multiplication (convolution), often accelerated with NTT (see the 998244353 modulus in Modular Arithmetic), to compute an entire sequence’s terms in bulk rather than one value at a time.
Stirling Numbers
First kind — number of permutations of elements with exactly cycles:
Second kind — number of ways to partition a set of labeled elements into exactly non-empty subsets:
vector<vector<long long>> stirlingSecondKind(int n, long long mod) {
vector<vector<long long>> S(n + 1, vector<long long>(n + 1, 0));
S[0][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= i; j++)
S[i][j] = (S[i - 1][j - 1] + 1LL * j * S[i - 1][j]) % mod;
return S;
}Time Complexity:
Bell Numbers
Total number of ways to partition a set of labeled elements into any number of non-empty subsets:
Computed directly with the Bell triangle, avoiding the need to build the full Stirling table:
vector<long long> bellNumbers(int n, long long mod) {
vector<vector<long long>> tri(n + 1);
tri[0] = {1};
vector<long long> B(n + 1);
B[0] = 1;
for (int i = 1; i <= n; i++) {
tri[i].assign(i + 1, 0);
tri[i][0] = tri[i - 1][i - 1];
for (int j = 1; j <= i; j++)
tri[i][j] = (tri[i][j - 1] + tri[i - 1][j - 1]) % mod;
B[i] = tri[i][0];
}
return B;
}Time Complexity:
Partition Numbers
The integer partition function counts the number of ways to write as a sum of positive integers, ignoring order.
Computed with a coin-change-style DP that builds every value up to using parts :
vector<long long> partitionNumbers(int n, long long mod) {
vector<long long> p(n + 1, 0);
p[0] = 1;
for (int part = 1; part <= n; part++)
for (int i = part; i <= n; i++)
p[i] = (p[i] + p[i - part]) % mod;
return p;
}Time Complexity:
Space Complexity:
Recurrence Relations
A linear homogeneous recurrence with constant coefficients has the form
Its behavior is governed by the characteristic equation
whose roots give the closed form (for distinct roots), with the fixed by the initial conditions.
For competitive programming, the practical takeaway is that any such recurrence can be evaluated for huge in by encoding one step of the recurrence as a transition matrix and applying Matrix Exponentiation. For example, Fibonacci’s becomes
Pigeonhole Principle
Naive form. If more than objects are placed into boxes, at least one box contains more than one object.
General form. If pigeons are placed into holes, at least one hole contains at least pigeons.
Generalized form. If more than objects are placed into boxes, at least one box contains more than objects.
Application is usually a two-step process: identify what the “pigeons” and “holes” are, then finish with problem-specific reasoning once the principle guarantees a collision.