Перейти до основного вмісту

Знаходження степеня дільника факторіала

Задано два числа nn і kk. Знайти найбільше ціле xx, таке що kxk^x ділить n!n!.

Коли підходить цей алгоритм?
  • Чи потрібно знайти, у якому степені дільник kk (або просте pp) входить у n!n! — без обчислення самого факторіала?
  • Чи nn величезне (так, що n!n! неможливо обчислити прямо), а ви хочете відповідь за O(logkn)O(\log_k n) через формулу Лежандра?
  • Якщо натомість потрібне саме значення n!modpn! \bmod p(→ Факторіал за модулем p)?

Просте kk

Спочатку розглянемо випадок простого kk. Явний вираз для факторіала має вигляд

n!=123(n1)nn! = 1 \cdot 2 \cdot 3 \ldots (n-1) \cdot n

Зауважимо, що кожен kk-тий елемент добутку ділиться на kk, тобто додає +1+1 до відповіді; кількість таких елементів дорівнює nk\Bigl\lfloor\dfrac{n}{k}\Bigr\rfloor.

Далі, кожен k2k^2-тий елемент ділиться на k2k^2, тобто додає ще +1+1 до відповіді (перший степінь kk ми вже врахували в попередньому абзаці). Кількість таких елементів дорівнює nk2\Bigl\lfloor\dfrac{n}{k^2}\Bigr\rfloor.

І так далі: для кожного ii кожен kik^i-тий елемент додає ще +1+1 до відповіді, і таких елементів є nki\Bigl\lfloor\dfrac{n}{k^i}\Bigr\rfloor.

Остаточна відповідь дорівнює

nk+nk2++nki+\Bigl\lfloor\dfrac{n}{k}\Bigr\rfloor + \Bigl\lfloor\dfrac{n}{k^2}\Bigr\rfloor + \ldots + \Bigl\lfloor\dfrac{n}{k^i}\Bigr\rfloor + \ldots

Цей результат також відомий як формула Лежандра. Сума, звісно, скінченна, бо лише приблизно перші logkn\log_k n доданків не є нулями. Отже, час роботи цього алгоритму становить O(logkn)O(\log_k n).

Реалізація


int fact_pow (int n, int k) {
int res = 0;
while (n) {
n /= k;
res += n;
}
return res;
}

Складене kk

Цю саму ідею не можна застосувати безпосередньо. Натомість ми можемо розкласти kk на множники, подавши його у вигляді k=k1p1kmpmk = k_1^{p_1} \cdot \ldots \cdot k_m^{p_m}. Для кожного kik_i ми знаходимо, скільки разів він входить у n!n!, за допомогою описаного вище алгоритму — назвемо це значення aia_i. Відповідь для складеного kk буде

mini=1maipi\min_ {i=1 \ldots m} \dfrac{a_i}{p_i}