Nth Magical Number

hard binary search math number theory

Problem

A positive integer is magical if it is divisible by a or by b. Given n, a, and b, return the nth smallest magical number, modulo 10⁹ + 7. The count of magical numbers ≤ x is x/a + x/b − x/lcm(a,b) (inclusion–exclusion), which is monotonic — so binary search for the smallest x whose count reaches n.

Inputn = 4, a = 2, b = 3
Output6
Magical numbers: 2, 3, 4, 6, … the 4th is 6.

from math import gcd

def nth_magical_number(n, a, b):
    lcm = a * b // gcd(a, b)
    lo, hi = 1, n * min(a, b)
    while lo < hi:
        mid = (lo + hi) // 2
        if mid // a + mid // b - mid // lcm >= n:
            hi = mid
        else:
            lo = mid + 1
    return lo % (10 ** 9 + 7)
function nthMagicalNumber(n, a, b) {
  const gcd = (x, y) => y ? gcd(y, x % y) : x;
  const lcm = a / gcd(a, b) * b;
  let lo = 1, hi = n * Math.min(a, b);
  while (lo < hi) {
    const mid = Math.floor((lo + hi) / 2);
    const cnt = Math.floor(mid / a) + Math.floor(mid / b) - Math.floor(mid / lcm);
    if (cnt >= n) hi = mid;
    else lo = mid + 1;
  }
  return lo % (1e9 + 7);
}
int nthMagicalNumber(int n, int a, int b) {
    long lcm = (long) a / gcd(a, b) * b;
    long lo = 1, hi = (long) n * Math.min(a, b);
    while (lo < hi) {
        long mid = (lo + hi) / 2;
        if (mid / a + mid / b - mid / lcm >= n) hi = mid;
        else lo = mid + 1;
    }
    return (int) (lo % 1_000_000_007);
}
private int gcd(int x, int y) { return y == 0 ? x : gcd(y, x % y); }
int nthMagicalNumber(int n, int a, int b) {
    long long lcm = (long long) a / __gcd(a, b) * b;
    long long lo = 1, hi = (long long) n * min(a, b);
    while (lo < hi) {
        long long mid = (lo + hi) / 2;
        if (mid / a + mid / b - mid / lcm >= n) hi = mid;
        else lo = mid + 1;
    }
    return lo % 1000000007;
}
Time: O(log(n·min(a,b))) Space: O(1)