Pigeonhole principle. If objects go into boxes, some box gets at least . The art is choosing the boxes.

PuzzleBoxesAnswer
socks of colours in the dark: how many to be sure of a pair?colours
… to be sure of socks of one colourcolours
10 black and 10 white socks, sure of a black pairworst case: all whites first
gloves: 10 pairs, sure of a matching left and rightworst case: all lefts
367 people: two share a birthday366 daysalways
among people, two have the same number of friends at the partydegrees , but and cannot both occuralways
handshake lemma: the number of people who shook an odd number of hands is evenalways
integers: a nonempty contiguous block with sum divisible by prefix sums mod always,
numbers from : two are coprimepairs two consecutive numbers
numbers from : one divides anotherodd parts same odd part, powers of 2 differ
5 lattice points: the midpoint of two is a lattice pointparities always
5 points in a unit square: two within four squaresalways
any distinct numbers: increasing run of or decreasing of (Erdős–Szekeres)labels (longest increasing ending here, longest decreasing ending here)always, tight
Dirichlet: for real and , some has fractional parts of in intervalsalways
two Londoners with the same number of hairshair counts populationalways
party of 6: three mutual friends or strangerssee Party ProblemRamsey
pair<int, int> divisibleBlock(const vector<ll>& a) {   // [l, r) with sum divisible by n = |a|
    int n = sz(a); vector<int> seen(n, -1); seen[0] = 0; ll s = 0;
    for (int i = 0; i < n; i++) {
        s = ((s + a[i]) % n + n) % n;
        if (seen[s] >= 0) return {seen[s], i + 1};
        seen[s] = i + 1;
    }
    return {-1, -1};                                   // unreachable for n >= 1
}
 
pair<int, int> dividingPair(const vector<int>& v) {   // distinct values in 1..2n, |v| = n + 1: indices i, j with v[i] | v[j]
    int n = sz(v) - 1; vector<int> byOdd(2 * n + 1, -1);
    for (int i = 0; i <= n; i++) {
        int o = v[i]; while (o % 2 == 0) o /= 2;
        if (byOdd[o] >= 0) { int j = byOdd[o]; return v[j] < v[i] ? pair{j, i} : pair{i, j}; }
        byOdd[o] = i;
    }
    return {-1, -1};
}
 
vector<int> erdosSzekeres(const vector<int>& a, int r, int s) {   // |a| >= r s + 1 distinct values
    int n = sz(a); vector<int> inc(n, 1), dec(n, 1), pi(n, -1), pd(n, -1);
    for (int i = 0; i < n; i++) for (int j = 0; j < i; j++) {
        if (a[j] < a[i] && inc[j] + 1 > inc[i]) inc[i] = inc[j] + 1, pi[i] = j;
        if (a[j] > a[i] && dec[j] + 1 > dec[i]) dec[i] = dec[j] + 1, pd[i] = j;
    }
    for (int i = 0; i < n; i++) {
        auto build = [&](const vector<int>& par) { vector<int> idx; for (int k = i; k >= 0; k = par[k]) idx.push_back(k); reverse(all(idx)); return idx; };
        if (inc[i] > r) { auto idx = build(pi); idx.resize(r + 1); return idx; }
        if (dec[i] > s) { auto idx = build(pd); idx.resize(s + 1); return idx; }
    }
    return {};                                         // only if |a| <= r s
}
 
pair<int, int> latticeMidpoint(const vector<pair<ll, ll>>& p) {   // >= 5 points: midpoint of p[i], p[j] is integral
    int first[4] = {-1, -1, -1, -1};
    for (int i = 0; i < sz(p); i++) {
        int c = int((p[i].first & 1) * 2 + (p[i].second & 1));
        if (first[c] >= 0) return {first[c], i};
        first[c] = i;
    }
    return {-1, -1};
}