The factorial of an integer N, written N!, is the product of all the integers from 1 through N inclusive. The factorial quickly becomes very large: 13! is too large to store in a 32-bit integer on most computers, and 70! is too large for most floating-point variables. Your task is to find the rightmost non-zero digit of n!. For example, 5! = 1 * 2 * 3 * 4 * 5 = 120, so the rightmost non-zero digit of 5! is 2. Likewise, 7! = 1 * 2 * 3 * 4 * 5 * 6 * 7 = 5040, so the rightmost non-zero digit of 7! is 4.
PROGRAM NAME: fact4
INPUT FORMAT
A single positive integer N no larger than 4,220.
SAMPLE INPUT (file fact4.in)
7
OUTPUT FORMAT
A single line containing but a single digit: the right most non-zero digit of N! .
SAMPLE OUTPUT (file fact4.out)
4
题意:
给出一个数 N (1 ~ 4220),求出 N!,输出最右第一个非零的数。
思路:
数学。我的做法是直接保存后面的 K 位数,一旦有 0 就不断删除 0,最后输出 % 10 的答案即可。
官方解答是找出 2 和 5 的对数,因为 2 X 5 或者 5 X 2 是使末尾变为 0 的关键,所以找出 1 ~ N 中因子 2 的个数和因子 5 的个数,排除最大对数的 2 和 5 之后,剩下的数相乘就不会产生进位了,那么直接保存最后一位相乘的结果就好。因为 2 的个数肯定要比 5 的个数多,所以 5 的个数即为最大的对数,所以最后还要乘上剩下未匹配的 2,即乘上 (n5 - n2)个 2 后才是结果。
AC1:
/*
TASK:fact4
LANG:C++
ID:sum-g1
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
int main() {
freopen("fact4.in", "r", stdin);
freopen("fact4.out", "w", stdout);
int n;
scanf("%d", &n);
ll last = 1;
for (int i = 1; i <= n; ++i) {
last *= i;
while (!(last % 10)) last /= 10;
last %= 100000000000;
}
printf("%lld\n", last % 10);
return 0;
}
AC2:
/*
TASK:fact4
LANG:C++
ID:sum-g1
*/
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
int main() {
freopen("fact4.in", "r", stdin);
freopen("fact4.out", "w", stdout);
int n;
scanf("%d", &n);
int n2 = 0, n5 = 0, last = 1;
for (int i = 1; i <= n; ++i) {
int j = i;
while (!(j % 2)) {
++n2;
j /= 2;
}
while (!(j % 5)) {
++n5;
j /= 5;
}
last = (last * j) % 10;
}
for (int i = 1; i <= n2 - n5; ++i)
last = (last * 2) % 10;
printf("%d\n", last);
return 0;
}