Разбор
Вычисления будем проводить с использованием -разрядных беззнаковых целых чисел (unsigned long long). Очевидно, что
Присвоим переменной значение , после чего будем ее умножать на для всех от до . Каждый раз деление на будет целочисленным, однако при умножении можно получить переполнение. Пусть . Тогда операцию
перепишем через
При такой реализации переполнения при умножении не произойдет (ответ является -разрядным беззнаковым целым числом). Заметим, что сначала следует выполнить деление , а потом умножение на полученное частное.
Для вычисления следует выполнить итераций. Но что делать, если следует вычислить ? Ответ не превысит , поэтому такие входные данные возможны. Поскольку , то при следует положить .
Пример
Рассмотрим следующий пример:
Пусть , и осталось выполнить умножение . Вычислим . Поэтому .
Реализация алгоритма
Функция gcd вычисляет наибольший общий делитель чисел и .
unsigned long long gcd(unsigned long long a, unsigned long long b) { return (!b) ? a : gcd(b,a % b); }
Функция Cnk вычисляет значение биномиального коэффициента .
unsigned long long Cnk(unsigned long long n, unsigned long long k) { unsigned long long CnkRes = 1, t, i; if (k > n - k) k = n - k; for(i = 1; i <= k; i++) { t = gcd(CnkRes, i); CnkRes = (CnkRes / t) * ((n - i + 1) / (i / t)); } return CnkRes; }
Основная часть программы. Читаем входные данные. Последовательно обрабатываем тесты.
scanf("%d",&t); while(t--) { scanf("%llu %llu",&n,&k); res = Cnk(n,k); printf("%llu\n",res); }
Java реализация
В Java отсутствуют unsigned типы, поэтому следует воспользоваться классом BigInteger.
import java.util.*; import java.math.*; public class Main { static BigInteger Cnk(BigInteger n, BigInteger k) { BigInteger ONE = BigInteger.ONE, CnkRes = ONE; if (k.compareTo(n.subtract(k)) > 0) k = n.subtract(k); for(BigInteger i = ONE; i.compareTo(k) <= 0; i = i.add(ONE)) CnkRes = CnkRes.multiply(n.subtract(i).add(ONE)).divide(i); return CnkRes; } public static void main(String[] args) { Scanner con = new Scanner(System.in); int tests = con.nextInt(); while(tests-- > 0) { BigInteger n = con.nextBigInteger(); BigInteger k = con.nextBigInteger(); BigInteger res = Cnk(n,k); System.out.println(res); } } }
Python реализация – comb
Для вычисления биномиального коэффициента воспользуемся встроенной функцией .
import math
Читаем количество тестов .
t = int(input()) for _ in range(t):
Читаем входные данные текущего теста.
n, k = map(int, input().split())
Вычисляем и выводим ответ.
res = math.comb(n, k) print(res)
Python реализация
Функция Cnk вычисляет значение биномиального коэффициента .
def Cnk(n, k): res = 1 if k > n - k: k = n – k for i in range(1, k + 1): res = res * (n - i + 1) // i return res
Основная часть программы. Читаем количество тестов .
t = int(input()) for _ in range(t):
Читаем входные данные текущего теста.
n, k = map(int, input().split())
Вычисляем и выводим ответ.
res = Cnk(n, k) print(res)