Разбор
Если , то . Достаточно найти решение и вместе с парой вывести также пару . При эти две пары совпадают.
Пусть — наименьшее число, для которого . Тогда очевидно что .
Зафиксируем такое что и рассмотрим функцию . Тогда при функция является монотонно возрастающей. Следовательно можно решить уравнение бинарным поиском.
Таким образом для решения задачи следует перебрать значения и для каждого такого решить уравнение относительно бинарным поиском. Найденное значение должно быть целочисленным.
Пример
Рассмотрим уравнение . Учитывая что , а , то нам достаточно перебрать .
Пусть , рассмотрим уравнение или , . Бинарным поиском в промежутке находим целочисленное решение . Учитывая что , имеем два решения: .
Реализация алгоритма
Искомые пары будем хранить в векторе пар .
vector<pair<long long,long long> > res;
Функция Cnk вычисляет значение биномиального коэффициента .
long long Cnk(long long n, long long k) { long long i, Res = 1; if (k > n - k) k = n - k; for(i = 1; i <= k; i++) {
Если на очередной итерации результат превосходит (мы ищем решение уравнения ), то останавливаемся. Таким выходом из функции мы также избежим переполнения.
if (1.0 * Res * (n - i + 1) / i > m) return m + 1; Res = Res * (n - i + 1) / i; } return Res; }
Основная часть программы. Читаем входные данные.
scanf("%d",&tests); while (tests--) { res.clear(); scanf("%lld",&m);
Перебираем значение от до тех пор пока .
for(k = 0; Cnk(2*k,k) <= m; k++) {
Ищем значение бинарным поиском.
long long lo = 2*k, hi = m; while (lo < hi) { long long n = (lo + hi) / 2; if (Cnk(n,k) < m) lo = n + 1; else hi = n; }
Если , то решение найдено. Заносим в результат одну или две пары решений.
if (Cnk(lo,k) == m) { res.push_back(make_pair(lo,k)); if (lo != 2*k) res.push_back(make_pair(lo,lo - k)); } }
Сортируем пары.
sort(res.begin(),res.end());
Выводим ответ — количество найденных пар и сами пары.
printf("%d\n",res.size()); for(i = 0; i < res.size(); i++) printf("(%lld,%lld) ", res[i].first,res[i].second); printf("\n"); }
Python реализация
Функция Cnk вычисляет значение биномиального коэффициента .
def Cnk(n, k): Res = 1 if k > n - k: k = n – k for i in range(1, k + 1):
Если на очередной итерации результат превосходит (мы ищем решение уравнения ), то останавливаемся. Таким выходом из функции мы также избежим переполнения.
if Res * (n - i + 1) // i > m: return m + 1 Res = Res * (n - i + 1) // i return Res
Основная часть программы. Читаем входные данные.
tests = int(input()) for _ in range(tests): res = [] m = int(input())
Перебираем значение от до тех пор пока .
k = 0 while Cnk(2 * k, k) <= m:
Ищем значение бинарным поиском.
lo, hi = 2 * k, m while lo < hi: n = (lo + hi) // 2 if Cnk(n, k) < m: lo = n + 1 else: hi = n
Если , то решение найдено. Заносим в результат одну или две пары решений.
if Cnk(lo, k) == m: res.append((lo, k)) if lo != 2 * k: res.append((lo, lo - k)) k += 1
Сортируем пары.
res.sort()
Выводим ответ — количество найденных пар и сами пары.
print(len(res)) for item in res: print(f"({item[0]},{item[1]})", end=" ") print()