The number families behind set partitions, cycle structures and integer partitions: Stirling numbers of both kinds, Bell, Lah, Fubini, Eulerian, Motzkin, Schröder, Delannoy, partition numbers (all, bounded, distinct parts) and the -binomial. Tables are templates over T (a mint from Modular Arithmetic or an exact integer type: ll overflows quickly, , ); functions that divide need a prime modulus. Catalan, Narayana and lattice paths are in Catalan and Lattice Paths, derangements in Inclusion–Exclusion.
| Number | Counts | Recurrence / formula | Start |
|---|---|---|---|
| (unsigned first kind) | permutations of with cycles | ; | row 4: 6, 11, 6, 1 |
| (second kind) | partitions of into non-empty blocks | ; | row 4: 1, 7, 6, 1 |
| Bell | all set partitions of | ; ; EGF | 1, 1, 2, 5, 15, 52, 203, 877, 4140 |
| Lah | partitions of into non-empty ordered lists | row 3: 6, 6, 1 | |
| Fubini | ordered set partitions (weak orders, race rankings with ties) | ; | 1, 1, 3, 13, 75, 541 |
| Eulerian | permutations with ascents | row 4: 1, 11, 11, 1 | |
| Motzkin | paths U/D/F staying ; non-crossing chords (not all points used) | 1, 1, 2, 4, 9, 21, 51, 127 | |
| large Schröder | paths E/N/NE under the diagonal; separable permutations () | 1, 2, 6, 22, 90, 394 | |
| Delannoy | paths E/N/NE, unrestricted | : 1, 3, 13, 63 | |
| integer partitions | Euler’s pentagonal recurrence; | 1, 1, 2, 3, 5, 7, 11, 15, 22, 30, 42 | |
| partitions into exactly parts (= largest part ) | |||
| partitions into distinct parts (= into odd parts) | 1, 1, 1, 2, 2, 3, 4, 5, 6, 8 |
| Identity | Use |
|---|---|
| , | row sums |
| ; ; | change of basis between powers and falling factorials: sums of , moments of random variables |
| surjections : | the twelvefold way (Counting Fundamentals) |
| ; Worpitzky | |
| conjugation: partitions with at most parts = partitions with all parts | Ferrers diagram transpose |
| (Hardy–Ramanujan) | , has 107 digits |
| a whole row or , , in | NTT: convolution, Taylor shift, , inverse of the pentagonal series (Counting with Power Series) |
template <class T> vector<vector<T>> stirling1Table(int n) { // c[i][j], unsigned
vector<vector<T>> s(n + 1, vector<T>(n + 1, T(0))); s[0][0] = T(1);
for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) s[i][j] = s[i - 1][j - 1] + T(i - 1) * s[i - 1][j];
return s;
}
template <class T> vector<vector<T>> stirling2Table(int n) { // S[i][j]
vector<vector<T>> s(n + 1, vector<T>(n + 1, T(0))); s[0][0] = T(1);
for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) s[i][j] = s[i - 1][j - 1] + T(j) * s[i - 1][j];
return s;
}
mint stirling2(ll n, int k, const Comb& cb) { // one S(n, k), huge n, O(k log n); cb covers k
if (k < 0 || k > n) return 0;
mint res = 0;
for (int j = 0; j <= k; j++) { mint t = mint(j).pow(n) * cb.fi[j] * cb.fi[k - j]; res += (k - j) % 2 ? -t : t; }
return res;
}
template <class T> vector<T> bellNumbers(int n) { // Bell triangle, O(n^2)
vector<T> bell(n + 1), row = {T(1)}; bell[0] = T(1);
for (int i = 1; i <= n; i++) {
vector<T> next = {row.back()};
for (const T& x : row) next.push_back(next.back() + x);
row = move(next); bell[i] = row[0];
}
return bell;
}
template <class T> vector<T> partitionNumbers(int n) { // p(0..n), pentagonal recurrence, O(n sqrt n)
vector<T> p(n + 1, T(0)); p[0] = T(1);
for (int i = 1; i <= n; i++)
for (int k = 1;; k++) {
ll g1 = (ll)k * (3 * k - 1) / 2, g2 = (ll)k * (3 * k + 1) / 2;
if (g1 > i) break;
T s = p[i - g1]; if (g2 <= i) s += p[i - g2];
if (k % 2) p[i] += s; else p[i] -= s;
}
return p;
}
template <class T> vector<T> partitionsMaxPart(int n, int k) { // partitions of 0..n with all parts <= k (coin-change DP), O(nk)
vector<T> p(n + 1, T(0)); p[0] = T(1);
for (int part = 1; part <= k; part++) for (int i = part; i <= n; i++) p[i] += p[i - part];
return p;
}
template <class T> vector<vector<T>> partitionsIntoParts(int n, int k) { // P[i][j]: i into exactly j parts
vector<vector<T>> p(n + 1, vector<T>(k + 1, T(0))); p[0][0] = T(1);
for (int i = 1; i <= n; i++) for (int j = 1; j <= min(i, k); j++) p[i][j] = p[i - 1][j - 1] + p[i - j][j];
return p;
}
template <class T> vector<T> distinctPartitions(int n) { // q(0..n), O(n sqrt n)
vector<T> q(n + 1, T(0)), cur(n + 1, T(0)); q[0] = cur[0] = T(1); // cur[i]: i into exactly j distinct parts
for (int j = 1; j * (j + 1) / 2 <= n; j++) {
vector<T> nxt(n + 1, T(0));
for (int i = j; i <= n; i++) nxt[i] = nxt[i - j] + cur[i - j];
cur = nxt;
for (int i = 0; i <= n; i++) q[i] += cur[i];
}
return q;
}Proof: Stirling, Bell and partition recurrences
First kind. Element is a fixed point (a new cycle: ) or is inserted after one of the other elements in its cycle (). The rising factorial satisfies the same recurrence coefficientwise, and gives the signed version. Second kind. Element is a singleton block or joins one of blocks. The closed form is inclusion–exclusion for surjections onto labelled boxes divided by (blocks are unlabelled and non-empty, so each partition corresponds to exactly surjections). Power basis: both sides of count functions for every positive integer (group by the partition of into fibres; the fibres get distinct values in ways); polynomials agreeing at infinitely many points are equal. Row sums: permutations by cycle count, set partitions by block count.
Bell. In a partition of , the block of contains other elements; the remaining are partitioned arbitrarily: . Bell triangle: with and , induction on gives : the recurrence becomes Pascal’s rule after shifting by one in the first term. Hence and , which is the first entry of the next row. EGF: a set partition is a set of non-empty blocks, so its EGF is .
Partitions. Pentagonal number theorem: . Franklin’s involution: in a partition into distinct parts, let be the smallest part and the length of the run of consecutive parts starting at the largest; move the smallest part onto the top run (one cell to each of the largest parts) if , else move the run’s last column into a new smallest part. This changes the number of parts by , so it pairs partitions with opposite signs, and it is undefined exactly for the pentagonal shapes , which carry sign . Multiplying by this series gives 1, which is the recurrence in
partitionNumbers. Bounded parts: the coin DP adds parts of sizepartin nondecreasing order of size, so each multiset of parts is counted once. Exactly parts: either a part equals 1 (remove it) or all parts are (subtract 1 from each). Distinct parts: subtract 1 from each of the parts; a part 1 disappears ( parts remain) or not. Euler: . Conjugation: transposing the Ferrers diagram swaps the number of parts and the largest part. The asymptotic is Hardy–Ramanujan’s theorem (circle method), quoted. All tables were checked against brute-force enumeration (permutations, set partitions via restricted growth strings, integer partitions) for .
More families
template <class T> vector<vector<T>> eulerianTable(int n) { // E[i][k]: permutations of i with k ascents
vector<vector<T>> e(n + 1, vector<T>(n + 1, T(0))); e[0][0] = T(1);
for (int i = 1; i <= n; i++) for (int k = 0; k < i; k++) e[i][k] = T(k + 1) * e[i - 1][k] + (k ? T(i - k) * e[i - 1][k - 1] : T(0));
return e;
}
template <class T> vector<T> motzkin(int n) { // prime modulus (division)
vector<T> m(n + 1, T(1));
for (int i = 2; i <= n; i++) m[i] = (T(2 * i + 1) * m[i - 1] + T(3 * i - 3) * m[i - 2]) / T(i + 2);
return m;
}
template <class T> vector<T> schroder(int n) { // large Schroder, O(n^2)
vector<T> s(n + 1, T(0)); s[0] = T(1); if (n >= 1) s[1] = T(2);
for (int i = 2; i <= n; i++) { s[i] = T(3) * s[i - 1]; for (int k = 1; k <= i - 2; k++) s[i] += s[k] * s[i - 1 - k]; }
return s;
}
template <class T> vector<vector<T>> delannoyTable(int n, int m) {
vector<vector<T>> d(n + 1, vector<T>(m + 1, T(1)));
for (int i = 1; i <= n; i++) for (int j = 1; j <= m; j++) d[i][j] = d[i - 1][j] + d[i][j - 1] + d[i - 1][j - 1];
return d;
}
template <class T> vector<vector<T>> lahTable(int n) { // L(i, k) = L(i-1, k-1) + (i - 1 + k) L(i-1, k)
vector<vector<T>> l(n + 1, vector<T>(n + 1, T(0))); l[0][0] = T(1);
for (int i = 1; i <= n; i++) for (int k = 1; k <= i; k++) l[i][k] = l[i - 1][k - 1] + T(i - 1 + k) * l[i - 1][k];
return l;
}
template <class T> vector<T> fubini(int n) { // F(i) = sum_{j>=1} C(i, j) F(i - j)
vector<vector<T>> c(n + 1, vector<T>(n + 1, T(0)));
for (int i = 0; i <= n; i++) { c[i][0] = T(1); for (int j = 1; j <= i; j++) c[i][j] = c[i - 1][j - 1] + c[i - 1][j]; }
vector<T> f(n + 1, T(0)); f[0] = T(1);
for (int i = 1; i <= n; i++) for (int j = 1; j <= i; j++) f[i] += c[i][j] * f[i - j];
return f;
}Proof: Eulerian, Lah, Fubini, Motzkin, Schröder, Delannoy
Eulerian. Insert into a permutation of with ascents. At the front, or inside an ascent (giving ), the ascent count is unchanged: slots. At the end, or inside a descent , it grows by one: slots. Hence . Worpitzky: count words for a positive integer . Sort the positions stably by value; the resulting permutation has , with strict inequality at every descent (equal values keep positions in increasing order). Conversely each and each such value sequence give exactly one word. With forced strict steps, subtracting from each value the number of forced steps before it leaves a weakly increasing sequence in : choices. Since , for all positive integers , hence as polynomials.
Lah. Write the elements in a row (), cut into non-empty consecutive lists ( cut positions), and forget the order of the lists (, they are distinct). Recurrence: element forms its own list, or is inserted into one of the lists at one of positions (before each of the elements or at the end of a list). Fubini. An ordered set partition is an ordered sequence of blocks (), or: choose the first block (, ) and order the rest.
Motzkin. A path starts with F (then any path of length ) or with U, a path of length , D, and the rest: , i.e. . Put with . Then , so . With , the coefficient of for reads , i.e. for . Schröder. Draw the paths as U, D and double-length flat steps F staying : a path is F followed by a path () or U D (); separating the terms and gives . Delannoy: classify by the last step. All tables were checked against brute force (ascent counts over permutations, list partitions, ordered partitions, and enumerated paths).
q-binomials
counts -dimensional subspaces of ( a prime power); as a polynomial in it is over binary words with ones and zeros, i.e. the generating function of partitions inside a box by size, and of inversions of multiset permutations. At it is the ordinary binomial.
template <class Z> struct QBinomial { // [n k]_q mod a prime, O(maxN) build, O(1) query (q-Lucas)
Z q; int d; vector<Z> qfact, qinv; // d: multiplicative order of q (or maxN + 1)
QBinomial(Z qq, int maxN) : q(qq), d(maxN + 1) {
Z cur = 1;
for (int i = 1; i <= maxN; i++) { cur *= q; if (cur == Z(1)) { d = i; break; } }
int m = min(d - 1, maxN); qfact.assign(m + 1, Z(1)); Z qi = 1;
for (int i = 1; i <= m; i++) qi *= q, qfact[i] = qfact[i - 1] * (Z(1) - qi);
qinv.resize(m + 1); for (int i = 0; i <= m; i++) qinv[i] = Z(1) / qfact[i];
}
Z reduced(int n, int k) const { return k < 0 || k > n ? Z(0) : qfact[n] * qinv[k] * qinv[n - k]; } // n < d
Z binom(ll a, ll b) const { if (b < 0 || b > a) return Z(0); Z r = 1; for (ll i = 0; i < b; i++) r = r * Z(a - i) / Z(i + 1); return r; }
Z C(int n, int k) const {
if (k < 0 || k > n) return Z(0);
if (n < d) return reduced(n, k);
return binom(n / d, k / d) * reduced(n % d, k % d);
}
};
template <class Z> vector<vector<Z>> qBinomialTable(int n, Z q) { // [i j] = [i-1 j-1] + q^j [i-1 j], O(n^2), any ring
vector<vector<Z>> t(n + 1, vector<Z>(n + 1, Z(0))); vector<Z> qp(n + 1, Z(1));
for (int i = 1; i <= n; i++) qp[i] = qp[i - 1] * q;
for (int i = 0; i <= n; i++) { t[i][0] = Z(1); for (int j = 1; j <= i; j++) t[i][j] = t[i - 1][j - 1] + qp[j] * t[i - 1][j]; }
return t;
}Proof: q-binomial recurrence, product formula, subspaces and q-Lucas
Recurrence. Let over words with ones and zeros, an inversion being a 1 before a 0. If the last letter is 1 it is in no inversion (); if it is 0 it forms an inversion with each of the ones (). Product formula: both sides satisfy this recurrence with the same boundary values; for the product, . Subspaces: ordered bases of a -dimensional subspace of number in total, and each subspace has of them; the quotient is the product formula. Box partitions: the 1s of a word, read with the number of 0s before each, form a partition with at most parts, each , whose size is the inversion count.
q-Lucas. Let have multiplicative order modulo . The q-binomial theorem holds by induction on : multiplying by needs , the q-Pascal rule obtained by classifying words by their first letter (a leading 1 precedes all zeros). For the factors with group into full periods, each equal to (the roots are , all -th roots of , and the constant term is 1). So , and for with the coefficient of comes only from in the first factor and in the second: . On the left the coefficient is with . The powers are all the roots of , so their product is , and ; hence . Cancelling gives . The code’s
reducedneeds so that every is invertible. Checked against the inversion-count definition and against the table for random , including of small order.
Related notes
- Counting Fundamentals (twelvefold way)
- Generating Functions
- Counting with Power Series (rows in )