Turn an optimisation problem into a feasibility problem, then binary search. One of the highest-value patterns in competitive programming.
The pattern
optimise f(x) --> binary search x, asking "is x achievable?"
It applies whenever the feasibility predicate is monotone: if works, every larger (or every smaller) value works too.
long long lo = LOW, hi = HIGH, ans = -1;
while (lo <= hi) {
long long mid = lo + (hi - lo) / 2;
if (feasible(mid)) { ans = mid; hi = mid - 1; } // minimising
else lo = mid + 1;
}Recognising it
The giveaway phrases:
| Statement says | Predicate |
|---|---|
| ”minimise the maximum…" | "can the maximum be ?" |
| "maximise the minimum…" | "can the minimum be ?" |
| "minimum time / cost such that…" | "is enough?" |
| "largest such that…" | "does work?" |
| "minimum number of groups…" | "do groups suffice?” |
Minimax and maximin objectives are almost always binary search. Recognising this replaces a hard DP with a greedy check.
Worked examples
Split an array into parts, minimising the largest part sum
bool feasible(long long X, int k) {
int parts = 1; long long cur = 0;
for (long long v : a) {
if (v > X) return false; // a single element exceeds X
if (cur + v > X) { parts++; cur = 0; }
cur += v;
}
return parts <= k;
}
// binary search X in [max(a), sum(a)]— versus for the DP. Always check for this before writing the DP.
Place cows in stalls maximising the minimum gap
feasible(d): greedily place cows at least apart; feasible iff at least fit.
Minimum capacity to ship all packages in days
feasible(cap): greedily fill days; feasible iff days used .
-th smallest element of an sorted matrix
count(X): number of elements , computed by a staircase walk in . Binary search over the value range: .
Maximum average subarray of length
feasible(avg): subtract avg from every element; is there a subarray of length with a non-negative sum? Computable with prefix sums and a running minimum in . Binary search avg over reals.
This last one — subtract the candidate average and look for a positive sum — is a technique worth internalising; it converts fractional objectives into linear ones.
Fractional programming (Dinkelbach)
To maximise , binary search and test whether is achievable. Each test is a linear problem.
This solves:
- minimum ratio cycle (average edge weight) — see Karp;
- maximum density subgraph (with a min cut per test);
- optimal cost-to-time ratio scheduling.
Dinkelbach’s iteration (repeatedly setting to the current best ratio) usually converges in a handful of steps — faster than binary search in practice.
Binary search + a data structure
The feasibility check can itself be non-trivial:
| Check | Cost |
|---|---|
| Greedy scan | |
| DP | |
| Max flow | e.g. “can we schedule everything by time “ |
| Matching | ”is there a perfect matching using only edges ” (bottleneck matching) |
| 2-SAT | ”is there an assignment with separation “ |
| Connectivity | ”is the graph connected using only edges ” |
The combination binary search + 2-SAT and binary search + flow are both standard and worth recognising.
Pitfalls
Check monotonicity
If the predicate is not monotone, binary search returns an arbitrary boundary — plausible, and wrong. When unsure, brute-force
feasible(X)for all on a small input and confirm the pattern isF...FT...T.
- Set
hito a provable upper bound; too small silently clamps the answer. - With real values, use a fixed iteration count.
- With integers, decide whether you want the smallest true or the largest false, and stick to one template.
See also: Binary Search · Aliens Trick · Parallel Binary Search