Аналіз алгоритму
Нехай функція обчислює кількість натуральних чисел на проміжку [1; ], що діляться або на , або на . Ця кількість дорівнює
Нехай – шукане -те число. Тоді має бути таким найменшим натуральним числом, що . Його будемо шукати бінарним пошуком, починаючи з відрізка [; ] = [1; ]. Нехай = ( + ) / 2. Якщо , то пошук слід продовжувати на відрізку [; ], інакше – на відрізку [ + 1; ].
Приклад
Розглянемо перший приклад, в якому , . Необхідно знайти найменше , для якого . Вирахуємо деякі значення:
Найменшим розв'язком рівняння буде .
Реалізація алгоритму
Функції обчислення НСД і НСК.
long long gcd(long long a, long long b) { return (b == 0) ? a : gcd(b, a % b); } long long lcm(long long a, long long b) { return a / gcd(a, b) * b; }
Функція повертає кількість натуральних чисел, не більших , що діляться або на , або на .
long long f(long long n) { return n / a + n / b - n / lcm(a, b); }
Читаємо вхідні дані.
scanf("%lld %lld %lld", &a, &b, &n);
Запускаємо бінарний пошук. Шукаємо найменше значення , для якого .
left = 1; right = 1e9; while (left < right) { middle = (left + right) / 2; if (f(middle) >= n) right = middle; else left = middle + 1; }
Виводимо відповідь.
printf("%lld\n", left);
Java реалізація
import java.util.*; import java.io.*; public class Main { static long gcd(long a, long b) { return (b == 0) ? a : gcd(b, a % b); } static long lcm(long a, long b) { return a / gcd(a, b) * b; } static long f(long n, long a, long b) { return n / a + n / b - n / lcm(a, b); } public static void main(String[] args) { FastScanner con = new FastScanner(new InputStreamReader(System.in)); long a = con.nextInt(); long b = con.nextInt(); long n = con.nextInt(); long left = 1, right = 1000000000; while (left < right) { long middle = (left + right) / 2; if (f(middle, a, b) >= n) right = middle; else left = middle + 1; } System.out.println(left); } } class FastScanner { private BufferedReader br; private StringTokenizer st; public FastScanner(InputStreamReader reader) { br = new BufferedReader(reader); } public String next() { while (st == null || !st.hasMoreTokens()) { try { st = new StringTokenizer(br.readLine()); } catch (Exception e) { e.printStackTrace(); } } return st.nextToken(); } public int nextInt() { return Integer.parseInt(next()); } public void close() throws Exception { br.close(); } }