Almost every expectation problem is solved by one of: linearity over indicators, the tail-sum formula, conditioning on the first step (a DP or linear system), or a martingale / potential function with optional stopping. Answers are usually requested as : keep all probabilities as mint and never touch floating point. Expectation DPs are in Expected Value DP.

Rules

RuleStatement
conditional probability
total probability for a partition
Bayes
inclusion–exclusion / union bound$P(\bigcup A_i) = \sum_{\emptyset \ne S}(-1)^{
independence; pairwise independence does not imply mutual
linearity always
indicators
tail sum for ; for
total expectation
products only for independent (uncorrelated)
variance;
second moment of a count for

Distributions

Distribution
Bernoulli
binomial distribution
geometric distribution (trials until first success)
negative binomial (trials until successes)
hypergeometric (draw of , good)
Poisson
uniform on
exponential (density )—

Binomial Poisson as (rare events: number of collisions, of fixed points of a random permutation, of occurrences of a pattern). Geometric and exponential are memoryless: .

Classic expectations

QuantityValueWhy
fixed points of a random permutation (distribution Poisson(1)) indicators of probability
cycles / records (left-to-right maxima)position is a record with probability
inversionseach pair inverted with probability
local maxima (interior)each interior triple: probability
distinct values among uniform draws from value missing with probability
coupon collector: all sum of geometrics with
coupon collector: of the first phases
first repeated value (birthday); 50% at
randomized quicksort comparisonselements of ranks compared iff one is the first pivot among ranks :
depth of a key in a random BST / treapancestors are records in both directions
-th smallest of uniforms on points on a circle cut it into exchangeable gaps
maximum of fair -sided dicetail sum
double expectedMaxDice(int m, int k) { double e = 0; for (int t = 1; t <= m; t++) e += 1 - pow(double(t - 1) / m, k); return e; }
mint couponAll(int n) { mint s = 0; for (int i = 1; i <= n; i++) s += mint(n) / i; return s; }                  // n H_n
mint allCollectedBy(int n, ll t, const Comb& cb) {        // P(all n types seen within t draws), inclusion-exclusion
    mint s = 0; for (int k = 0; k <= n; k++) s += (k & 1 ? -1 : 1) * cb.C(n, k) * (mint(n - k) / n).pow(t); return s;
}
double birthdayNoCollision(ll n, ll k) { double p = 1; for (ll i = 0; i < k && p > 0; i++) p *= 1.0 - double(i) / n; return p; }

Birthday vs. coupon collector — two ends of the same occupancy process, easy to conflate: “when does the first collision happen” is (birthday — see Birthday Problem); “when has every value been seen” is (coupon collector — Coupon Collector). Generalizing birthday to a collision among items (not just 2) pushes the threshold to — a triple collision needs draws, which is what Wagner’s generalized birthday algorithm exploits for -sum problems. Generalizing coupon collector to “random walk visits every vertex” gives the cover time: for the complete graph, for a path or cycle, for any connected graph.

Both thresholds are the real engine behind several named algorithms, not just these two puzzles: Pollard’s rho and kangaroo (a random walk mod an unknown factor collides after steps), meet-in-the-middle and baby-step-giant-step ( from each half, matched by collision), and why an -bit cryptographic hash gives only bits of collision resistance. Practically: collides with probability near 1 after hashing only distinct strings (birthday with ), which is exactly why or double hashing is the right default modulus — see Hashing.

Martingales and potential functions

A sequence is a martingale if . Optional stopping: for a stopping time with and bounded increments (or bounded ), . The contest form: find a potential of the state with for every non-final state; then is a martingale and

which is often a constant (all final states share one potential). This solves processes whose state space is far too large for a DP: the potential is usually a sum of a function over parts (e.g. ), and the condition becomes a recurrence for .

ProcessResult
gambler’s ruin, fair, from in ,
biased ( up, down, ),
waiting time for a pattern in uniform letters over symbols$\sum_{k \text{ border of } s,\ k =
random walk on a tree, edge –$E[\text{hit } v \text{ from } u] = 2
random walk on a connected graphstationary ; return time to is
pair<double, double> gamblersRuin(ll i, ll N, double p) {  // {P(hit N before 0), expected duration}
    double q = 1 - p;
    if (fabs(p - q) < 1e-12) return {double(i) / N, double(i) * (N - i)};
    double r = q / p, P = (1 - pow(r, i)) / (1 - pow(r, N));
    return {P, i / (q - p) - N / (q - p) * P};
}
mint patternWaitingTime(const string& s, int sigma) {     // expected letters until s first appears
    int n = sz(s); vector<int> pi(n);
    for (int i = 1; i < n; i++) { int k = pi[i - 1]; while (k && s[i] != s[k]) k = pi[k - 1]; pi[i] = k + (s[i] == s[k]); }
    mint res = 0; for (int k = n; k > 0; k = pi[k - 1]) res += mint(sigma).pow(k);
    return res;
}

Markov chains

Distribution after steps: (matrix power in ). For an absorbing chain with transient part , the expected number of steps from each transient state solves , and absorption probabilities solve ; use Gaussian elimination (modular when exact answers are required, Gaussian Elimination). A state with self-loop probability and no other cycle back simply gets .

vector<double> expectedSteps(const vector<vector<double>>& P, const vector<char>& absorbing) {   // steps to absorption
    int k = sz(P); vector<vector<double>> A(k, vector<double>(k + 1));
    for (int i = 0; i < k; i++) {
        A[i][i] = 1;
        if (absorbing[i]) continue;
        for (int j = 0; j < k; j++) A[i][j] -= P[i][j];
        A[i][k] = 1;
    }
    for (int c = 0; c < k; c++) {                          // Gauss-Jordan with partial pivoting
        int piv = c; for (int r = c; r < k; r++) if (fabs(A[r][c]) > fabs(A[piv][c])) piv = r;
        swap(A[c], A[piv]);
        for (int r = 0; r < k; r++) if (r != c && A[r][c] != 0) { double f = A[r][c] / A[c][c]; for (int j = c; j <= k; j++) A[r][j] -= f * A[c][j]; }
    }
    vector<double> h(k); for (int i = 0; i < k; i++) h[i] = A[i][k] / A[i][i];
    return h;
}

Concentration

InequalityStatement
Markov for
Chebyshev$P(
Chernoff (sum of independent Bernoullis, mean ), for
Hoeffding (independent, values in , of them)$P(
union bound

Use them to argue that a randomized solution fails with tiny probability: repeat a Monte Carlo test times to push a one-sided error to ; a sum of many independent random choices stays within of its mean with high probability.