对应 POJ 题目:点击打开链接
Time Limit: 1500MS | Memory Limit: 65536K | |
Total Submissions: 15843 | Accepted: 9775 |
Description
Input
Output
Sample Input
6 3 60 100 1024 23456 8735373
Sample Output
0 14 24 253 5861 2183837
题意:求 n! 中末尾 0 的个数,比如 10! = 3628800,末尾有 2 个零。
思路:
1)直接求解 n!
// n = 17 爆 int
// n = 21 爆 long long
int fact1(int n){
LL ans = 1LL;
for(int i = 1; i <= n; i++)
ans *= i;
int count = 0;
while(ans){
int val = ans % 10;
if(!val) count++;
else break;
ans /= 10;
}
return count;
}
n 的最大值为 1,000,000,000,很明显上面方法不行
2)模拟大数乘法计算 n!,用数组存储结果
// 模拟大数乘法
int fact2(int n){
enum {SIZE = 3000};
int f[SIZE];
memset(f, 0, sizeof(f));
f[0] = 1;
for(int val = 2; val <= n; val++){
int carry = 0;
for(int i = 0; i < SIZE; i++){
f[i] = f[i] * val + carry;
carry = f[i] / 10;
f[i] %= 10;
}
}
int len = SIZE - 1;
while(!f[len]) len--;
int count = 0;
#if 0
for(int i = len; i >= 0; i--)
printf("%d", f[i]);
printf("\n");
#endif
for(int i = 0; i <= len; i++)
if(f[i] == 0) count++;
else break;
return count;
}
先不论空间是否够,上述算法时间复杂度为 O(n*m),m 为 n! 的长度,单是 n = 1,000,000,000 就超过了 1 秒能处理的操作数 100,000,000。不出所料 TLE
3)认真分析发现,n! = K * 10^M,所以结果就是求 M。而把 n! 分解成质因数相乘的形式为:n! = 2^x * 3^y * 5^z * ...;发现只有每一对 2 * 5 才能为结果添加一个 0,所以结果变成求 min{x, z}。而根据 n! 特性知道 x 必定大于 z,所以结果又变成求 z。也就是求 n! 的质因数相乘形式中 5 的指数;我们只需要判断 5 的倍数即可。
int fact3(int n){
int count = 0;
for(int val = 5; val <= n; val += 5){
int tmp = val;
while(tmp % 5 == 0){
count++;
tmp /= 5;
}
}
return count;
}
非常遗憾,时间复杂度为 O(n/5),TLE,理由同上。
4)在上面的启发下,可以使用类似的思路,就是
z = n / 5 + n / 5^2 + n / 5^3 ... + 0
可转换为不断用 n / 5,直到 n 为 0。比如 n = 100
100 / 5 = 20
20 / 5 = 4
4 / 5 = 0
那结果就是 20 + 4 + 0 = 24。
为什么可以这样?
其实 n / 5 意思就是取 n 以内的 5 的倍数的第一个 5(比如 50 = 5 * 5 * 2 就有 2 个 5)
n / 5^2 意思就是取 n 以内的 5 的倍数的第二个 5
...
举个例子,比如 n = 100
100 / 5 = 20
表示取 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 这些数的第一个 5(能被 5 整除)。
所有 5 的倍数都符合,故有 20 个。
100 / 5^2 = 4
表示取 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 这些数的第二个 5(能被 5^2 整除)。
只有 25, 50, 75, 100 这 4 个数符合。
100 / 5^3 = 0
表示取 5 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 这些数的第三个 5(能被 5^3 整除)。
没有符合要求的数字
把结果加起来就是 n! 的质因数相乘形式中 5 的指数。
int fact4(int n){
int count = 0;
while(n){
n /= 5;
count += n;
}
return count;
}