Skip to content

Instantly share code, notes, and snippets.

@tvolf
Created April 25, 2018 06:52
Show Gist options
  • Save tvolf/76be8cb33c7277992537d23a5fd0b3e3 to your computer and use it in GitHub Desktop.
Save tvolf/76be8cb33c7277992537d23a5fd0b3e3 to your computer and use it in GitHub Desktop.
Solution for task #88 on @unilecs telegram channel
<?php
/**
Пользуемся классической формулой вычисления биномиального коэффициента
Cnk = n! / (k! * (n - k)!)
значение k выбираем минимальным из k или (n - k) для уменьшения количества умножений
**/
function task88($n, $k) {
if ($k > $n) return '0';
// минимизируем $k, пользуясь свойством симметрии
if ($k > $n / 2) $k = $n - $k;
if ($k === 0) return '1';
$max = gmp_init('1' . str_repeat('0', 64), 2);
$numerator = gmp_init(1, 10);
$denominator = gmp_init(1, 10);
for ($i = 0; $i < $k; ++$i) {
$numerator = gmp_mul($numerator, strval($n - $i));
$denominator = gmp_mul($denominator, strval($i + 1));
// если на каком-то шаге превышено максимальное значение,
// возвращаем сообщение об ошибке
// мы можем делать такую проверку, так как у нас на каждом шаге
// отношение числитель/знаменатель всегда > 1,
// то есть, наш результат всегда растет
if (gmp_cmp(gmp_div_q($numerator, $denominator), $max) >= 0) {
return 'maximum value "' . gmp_strval($max) . '" exceeded';
}
}
return gmp_strval(gmp_div_q($numerator, $denominator));
}
function test($n, $k) {
printf("%d,%d => %s\n", $n, $k, task88($n, $k));
}
foreach([[5,10], [10,10], [10,9], [10,5], [100,50], [50,6], [2**32,2^10], [2**32,2**31]] as $e) test($e[0], $e[1]);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment