Use randomness to make an algorithm simpler, faster, or possible at all. The recurring theme: an adversary can construct a bad input for a deterministic algorithm, but cannot predict your coin flips. Hashing and verification are in Randomized Hashing and Verification, sampling and sketches in Sampling and Streaming, color coding and random-walk SAT in Randomized Search, heuristics in Heuristic Optimization.

Why randomness helpsExample
defeats adversarial inputrandom pivot in quicksort; a random hash base
avoids worst cases without analysistreaps instead of red-black trees
breaks symmetryleader election, Karger’s contraction
samples instead of enumeratingMonte Carlo integration
finds witnesses fastMiller–Rabin: most bases are witnesses
simplifies the coderandomized incremental geometry

Las Vegas and Monte Carlo

Las VegasMonte Carlo
outputalways correctmay be wrong with probability
running timea random variabledeterministic (or bounded)
guarantee”correct, probably fast""fast, probably correct”
failure moderuns long (TLE)wrong answer (WA)
complexity classZPPRP / co-RP (one-sided), BPP (two-sided)
examplesquicksort, quickselect, Pollard’s rho, Welzl, Seidel’s LP, treaps, randomized incremental Delaunay, hash tables with rehashingMiller–Rabin, Karger, Freivalds, string hashing, Tutte matrix test, Monte Carlo integration (two-sided, with an error bar), MCTS; simulated annealing has no guarantee at all
convertstop after a time budget and output anything: Monte Carlorepeat until a verifier accepts: Las Vegas, (Pollard’s rho: a random walk whose output is checked by division)

One-sided error is the useful kind. If one answer is always right (Miller–Rabin’s “composite”, Freivalds’ and hashing’s “different”), independent repetitions push the error to ; recognising which side is certain tells you where to add verification.

Per-run error Runs Total error
20
60
(Miller–Rabin per base)30

Rule of thumb: aim for an error below per submission, far below the probability of a hardware fault, for a handful of extra iterations.

In contestsSafe?
Las Vegas (randomized quicksort, treap)yes: always correct
hashing with a time-seeded baseyes: collision probability about
fixed-seed hashing or shufflingno: hackable (Codeforces has anti-tests for common seeds)
Miller–Rabin with the deterministic 64-bit basesyes: provably correct
Monte Carlo with erroryes in practice
simulated annealing on an exact-answer problemno
randomized algorithm on an interactive problem or a reproducibility-checking judgeread the statement
ClassMeaning
ZPPLas Vegas, expected polynomial time
RPone-sided error: never a false “yes”
co-RPone-sided the other way
BPPtwo-sided error
PPerror (much weaker; contains NP)

; whether is open but widely believed: randomness is expected to add convenience, not power. See Complexity Theory.

Las Vegas, carefully. Every output is valid; analyse the expected work over the random choices for every fixed legal input. Expected linear time is not a deadline; a heuristic that may silently fail is not Las Vegas merely because it retries; a retry limit changes the guarantee unless exhaustion is handled. Keep correctness and termination arguments separate (randomized pivots change quicksort’s running time, never the correctness of partitioning). Monte Carlo, carefully. Identify the random choices, state the failure bound, and union-bound over all comparisons or queries ( events of error give ). A fixed seed exposed to an adaptive adversary breaks the probability model, and two hashes are independent only if their randomness is; “large modulus” alone is not a proof.

Random numbers and shuffling

mt19937_64 rng(chrono::steady_clock::now().time_since_epoch().count() ^ (ull)new char);
ll randInt(ll l, ll r) { return uniform_int_distribution<ll>(l, r)(rng); }
 
template<class T> void fisherYates(vector<T>& v) {      // what std::shuffle(all(v), rng) does
    for (int i = sz(v) - 1; i > 0; i--) swap(v[i], v[randInt(0, i)]);
}
 
ll quickselect(vector<ll> a, int k) {                  // k-th smallest (0-based), expected O(n)
    int l = 0, r = sz(a) - 1;
    while (true) {
        if (l == r) return a[l];
        ll p = a[randInt(l, r)];
        int i = l, j = r, m = l;                       // 3-way partition: < p | == p | > p
        while (m <= j) { if (a[m] < p) swap(a[i++], a[m++]); else if (a[m] > p) swap(a[m], a[j--]); else m++; }
        if (k < i) r = i - 1; else if (k > j) l = j + 1; else return p;
    }
}

Never use a fixed seed, rand(), random_shuffle or srand(time(0))

A fixed seed is predictable and hackable. rand() is low quality (weak low bits) and rand() % n is biased when does not divide RAND_MAX + 1. random_shuffle used rand() and was removed in C++17. srand(time(0)) has one-second granularity: submissions in the same second share a seed. Seed from the clock, XOR an address in for extra entropy. The common shuffle bug swap(v[i], v[rand() % n]) (full range at every step) is not uniform.

What shuffling protectsKiller input without it
quicksort with the first element as pivotalready sorted:
Welzl’s enclosing circlepoints ordered so each is outside:
Seidel’s LP, randomized incremental Delaunayadversarial insertion order
Kuhn’s matchingadversarial adjacency order: shuffling adjacency lists is a cheap real speed-up against anti-Kuhn tests
hash tablescolliding keys: per operation
unbalanced BSTssorted insertion: a linked list

Probability tools

ToolStatement
linearity of expectation, no independence needed
union bound: crude but almost always enough
Markov:
Chebyshev
Chernoffindependent , , : , , so
backwards analysis”what is the probability that the last element added was important?”: clean expected bounds for randomized incremental algorithms (Seidel’s LP, Welzl, Delaunay)

Chernoff is what licenses “with high probability”: a sum of independent bounded variables is very close to its mean.

Derandomization

MethodIdea
conditional expectationsfix the random choices one at a time, always taking the branch whose conditional expectation stays at least the target
pairwise independencemany analyses need only pairwise independence: random bits, which can be enumerated
fixed witness setsMiller–Rabin with 7 fixed bases (or the first 12 primes) is deterministic for all 64-bit inputs: Primality and Factorization

Usually not worth it in practice, but conditional expectations is a genuine proof and construction technique. Example: a random side for every vertex cuts each edge with probability , so some cut has at least edges; fixing vertices greedily finds one deterministically.

vector<int> halfCut(int n, const vector<pair<int, int>>& edges) {   // >= m/2 cut edges (no self-loops), O(n + m)
    vector<vector<int>> adj(n); for (auto [u, v] : edges) adj[u].push_back(v), adj[v].push_back(u);
    vector<int> side(n, -1);
    for (int v = 0; v < n; v++) {                       // put v opposite to the majority of its placed neighbours
        int c0 = 0, c1 = 0;
        for (int u : adj[v]) if (side[u] == 0) c0++; else if (side[u] == 1) c1++;
        side[v] = c0 >= c1 ? 1 : 0;
    }
    return side;
}

Randomized algorithms worth knowing

AlgorithmRandomness used forNote
quicksort, nth_elementpivotSorting
treap, skip listpriorities, levelsTreaps, Data Structure Catalog
Miller–Rabin, Pollard’s rhowitnesses, the pseudo-random walkPrimality and Factorization
Karger, Karger–Steinrandom edge contractionGlobal Min Cut
Welzl, Seidel’s LPinsertion orderMinimum Enclosing Circle, Linear Programming
string hashing, Zobrist and set hashingthe base, random weightsHashing and Verification
Tutte matrix matchingmatrix entriesGeneral Matching
Freivalds’ check, Schwartz–Zippeltest vectors / pointsHashing and Verification
reservoir sampling, sketcheswhich item to keep, hash functionsSampling and Streaming
color coding, random-walk SATrandom colours, random flipsRandomized Search
simulated annealing, MCTSmove acceptance, playoutsHeuristic Optimization, Game Search

When randomness is not allowed (some interactive or hacking formats, reproducibility-checking judges), read the statement; otherwise randomize by default: it costs one line and removes a whole category of failure.