CP Notebook

← all snippets

FracBinarySearch

Given f and N, finds the smallest fraction p/q ∈ [0, 1] such that f(p/q) is true, and p, q ≤ N. You may want to throw an exception from f if it finds an exact solution, in which case N can be removed.

Time: O(log(N)) 25 lines stress-tested for n <= 300

Usage: fracBS([](Frac f) return f.p>=3*f.q; , 10); // 1,3

content/number-theory/FracBinarySearch.h — Lucian Bicsi, Simon Lindholm

struct Frac { ll p, q; };

template<class F>
Frac fracBS(F f, ll N) {
	bool dir = 1, A = 1, B = 1;
	Frac lo{0, 1}, hi{1, 1}; // Set hi to 1/0 to search (0, N]
	if (f(lo)) return lo;
	assert(f(hi));
	while (A || B) {
		ll adv = 0, step = 1; // move hi if dir, else lo
		for (int si = 0; step; (step *= 2) >>= si) {
			adv += step;
			Frac mid{lo.p * adv + hi.p, lo.q * adv + hi.q};
			if (abs(mid.p) > N || mid.q > N || dir == !f(mid)) {
				adv -= step; si = 2;
			}
		}
		hi.p += lo.p * adv;
		hi.q += lo.q * adv;
		dir = !dir;
		swap(lo, hi);
		A = B; B = !!adv;
	}
	return dir ? hi : lo;
}