Задача
Президент Першого національного Банку майор Томаса Б. Кiнгмена кожну ніч перекладає вміст сейфів, у яких клієнти банку зберігають свої коштовності. Грабіжникам це також відомо, і тому вони орендували один із сейфів у цьому банку й чекають, поки президент перекладе в їхній сейф щось цінне. Таким чином до їхніх рук потрапила скринька з коштовностями самого майора! Тепер у грабіжників є всього лиш кілька годин для того, щоб відкрити кодовий замок з трьох цифр, забрати цінності й повернути скриньку назад, щоб ніхто навіть не дізнався, що пограбування взагалі відбулося.
Знаючи пристасть майора до великих чисел, грабіжники переконані, що кодом є три послідовні цифри числа $N!$, що записують безпосередньо перед нулями наприкінці запису числа $N!$. Наприклад:
- при $N$ = $7$ кодом буде $504$, бо $7!$ = $5040$;
- при $N$ = $17$ кодом буде $096$, бо $17!$ = $355687428096000$.
За даним натуральним числом $N$ знайти три послідовні цифри числа $N!$, що записують безпосередньо перед нулями наприкінці запису числа $N!$.
Вхідні дані
Вхідний файл містить єдине ціле число $N$. $(7 \leqslant N \leqslant 1000000000)$.
Вихідні дані
Вихідний файл має містити рівно три цифри — шуканий код.
Тесты
№ | Входные данные | Выходные данные |
1 | 7 | 504 |
2 | 17 | 096 |
3 | 50 | 512 |
4 | 1000000000 | 144 |
Код
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 |
#include <iostream> #define COEF 10000000 #define TEN 10 using namespace std; unsigned int arr[] = { 1, 94194688,80754176,28792576,93638144,44194688,16269824,94550272,61946112,68933632, 68754176,19323648,22612992,36351232,57997312,66792576,2167808,95748096,88043776, 37690112,65638144,99247872,80831232,42968832,38960896,2194688,36401664,29433088, 21091328,35679232,40269824,3200512,39416576,62174976,23727104,49750272,52626176, 72337664,68916224,93513984,25146112,14722816,60257024,2170112,13989632,28933632, 91983872,29619968,23259904,52859904,2354176,61171456,14485248,81225984,93129472, 98123648,42294528,83940096,91339008,90945024,77812992,83786752,30308352,33122816, 709376,45551232,13495552,4053504,28486912,65094912,93197312,79194112,80894208, 48729344,89670656,26832576,59147776,51826688,14217984,72698112,10487808,29000448, 21455616,72560128,94383616,23588096,83462144,14917632,85698816,11810304,3083776, 84299264,11034368,6525952,27101696,68170112,92235008,45980416,15386112,44244224, 3398144 }; int main() { int N; unsigned long long factorial = 1; cin >> N; int idx = N/COEF; factorial = arr[idx]; int start = !N%COEF ? idx*COEF : idx*COEF + 1; if (N % COEF != 0) { for(int i = start; i <= N; i++) { factorial *= i; while(factorial % TEN == 0) factorial /= TEN; factorial %= COEF; } } factorial %= TEN*TEN*TEN; cout << factorial/(TEN*TEN) << (factorial/TEN)%TEN << factorial%TEN; return 0; } |
Решение
Поскольку процесс расчёта факториала больших чисел занимает много времени, его можно ускорить использованием массива факториалов некоторых чисел. Полное значение факториала не нужно, поэтому массив содержит последние $8$ ненулевых цифр значений факториалов чисел, кратных $10000000$, которые можно получить с помощью следующего кода:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
#include <iostream> #define TEN 10 using namespace std; int main() { int N = 1000000000, count = 1; unsigned long long factorial = 1; for(int i = 1; i <= N; i++) { factorial *= i; while(factorial%TEN == 0) factorial /= TEN; factorial %= 100000000; if (i % 10000000 == 0) {cout << factorial << ","; count++;} if (count == TEN) {cout << endl; count = 1;} } return 0; } |
Если на входе — число $N$, меньшее $10000000$, его факториал рассчитывается обычным циклом, попутно отбрасывая ненужные цифры высших разрядов. В конце выводятся искомые последние три цифры факториала числа $N$. Если на входе — число $N$, большее $10000000$, выбирается соответствующее значение из массива по индексу $N/10000000$, и далее с помощью цикла считается произведение оставшихся чисел из $N!$. С уменьшением кратности чисел, факториалы которых содержатся в массиве, увеличивается скорость выполнения программы.
Ссылки
- Код на ideone
- Задача на e-olymp
- Засчитанное решение на e-olymp
— Хорошее решение. Не был уверен, что Вы справитесь. Но если осилили, буду давать задачи сложнее. Молодец.
— Как вы получили числа из массива? Была какая-то вспомогательная программа?
— Почему у Вас на аватарке обезьянка?
— После «Наприклад:» должен идти маркированный список (UL). Для разметки элементов списка есть кнопки в редакторе, но проще написать самому пару тегов.
— Уберите пустые строки.
— Добавьте тесты для краев допустимого диапазона входных значений.
Была вспомогательная программа. Замечания исправила.
— Да, хорошо, что использовали вспомогательную программу. Это частая практика — предварительно что-то вычислить. Только нужно это написать и привести код.
— Пожалуйста, уберите кириллицу из адреса работы (постоянная ссылка).
Добавила этот код в описание решения. Ссылку изменила.