Binary Search
Classic Binary Search
Search for value x in a sorted array.
int l = 0, r = n - 1;
bool found = false;
while (l <= r) {
int m = (l + r) / 2;
if (x == v[m]) { found = true; break; }
else if (x > v[m]) l = m + 1;
else r = m - 1;
}
O(log n) per query.
Problems using this
A. Binary Search
Lower Bound (Closest to the Left)
Find the first index where a[i] >= x (or equivalently, the index where x would be inserted to keep sorted order).
Use r = l + 1 termination (avoids infinite loop):
int l = -1, r = n;
while (r > l + 1) {
int m = (l + r) / 2;
if (x > v[m]) l = m;
else r = m;
}
cout << r; // first index where v[r] >= x
When x > v[m], answer is to the right of m → l = m.
Otherwise answer is at or before m → r = m.
Problems using this
B. Closest to the Left
Upper Bound (Closest to the Right)
Find the first index where a[i] > x.
Same template, but compare with >= instead of >:
while (r > l + 1) {
int m = (l + r) / 2;
if (x >= v[m]) l = m; // x is >= v[m], go right
else r = m;
}
cout << r; // first index where v[r] > x
Problems using this
C. Closest to the Right
Binary Search on Answer
When the answer is a number and we can check “is x valid?” with a good(x) function that is monotonic (if good(x) is true, then good(x-1) is also true — or the opposite).
We binary search on the answer space instead of the array.
Example: What’s the maximum number of hamburgers we can make?
bool good(ll m) {
ll needB = max(0LL, freq[0] * m - b);
ll needS = max(0LL, freq[1] * m - s);
ll needC = max(0LL, freq[2] * m - c);
ll cost = needB * cb + needS * cs + needC * cc;
return money >= cost;
}
Find the range: start with l = 0, r = 1, double r until good(r) is false:
ll l = 0, r = 1;
while (good(r)) r *= 2;
while (r > l + 1) {
ll m = (l + r) / 2;
if (good(m)) l = m;
else r = m;
}
cout << l;
Problems using this
H. Hamburgers— max hamburgers with limited ingredientsB. Ropes— max length such that k ropes can be cutD. Children Holiday— max groupsG. Student Councils— max councilsA. Packing Rectangles— min container size
Binary Search on Doubles
When the answer is a real number (e.g. find x such that √x + x² >= c):
- Find upper bound by doubling until
good(r)is true. - Binary search with fixed iterations (100 is enough for precision):
double l = 0, r = 1;
while (!good(r)) r *= 2;
for (int i = 0; i < 100; i++) {
double m = (r + l) / 2;
if (good(m)) r = m;
else l = m;
}
cout << fixed << setprecision(15) << r;
For doubles, use for (int i = 0; i < 100; i++) instead of while (l <= r) to avoid precision issues.
Problems using this
E. Equation— find x where √x + x² = cB. Ropes— max rope piece length
Binary Search on Doubles (Maximize)
When we want the maximum valid value (e.g. max rope length):
double l = 0, r = 1e8;
for (int i = 0; i < 100; i++) {
double m = (r + l) / 2;
if (good(m)) l = m; // m works, try bigger
else r = m;
}
cout << l;
good(m) = can we cut at least k pieces of length m?
bool good(double x) {
int s = 0;
for (int i = 0; i < n; i++) s += floor(v[i] / x);
return s >= k;
}
Problems using this
B. Ropes
When to Use Binary Search on Answer
Ask yourself:
- Is the answer a number (integer or real)?
- Can I write a
good(x)function? - Is it monotonic — if
xworks, doesx-1also work (or vice versa)?
If yes to all three → binary search on answer.
Common patterns:
- “Maximum minimum” or “minimum maximum”
- “Can we achieve X with these resources?”
- “What’s the largest/smallest value such that condition holds?”