题目:
Mr. Santa asks all the great programmers of the world to solve a trivial problem. He gives them an integer m and asks for the number of positive integers n, such that the factorial of n ends with exactly m zeroes. Are you among those great programmers who can solve this problem?
Input
The only line of input contains an integer m (1 ≤ m ≤ 100 000) — the required number of trailing zeroes in factorial.
Output
First print k — the number of values of n such that the factorial of n ends with m zeroes. Then print these k integers in increasing order.
Examples
Input
1
Output
5
5 6 7 8 9
Input
5
Output
0
Note
The factorial of n is equal to the product of all integers from 1 to n inclusive, that is n! = 1·2·3·...·n.
In the first sample, 5! = 120, 6! = 720, 7! = 5040, 8! = 40320 and 9! = 362880.
题意:
给你一个m,让你给出n个数,这n个数中每个数的阶乘有m个0.
暴力规律:
思路:
阶乘说白了还是乘法,乘法可以分解成n个没有约数的数字,在这些数字的乘法中什么时候会产生0呢?毫无疑问只有当2*5的时候。所以一个阶乘中有几个5就会有几个0,因为只要是2的倍数就会提供2,一个数的阶乘中含的5的个数要比含有2的个数要少吧,所以2的数目是充足的,所以看阶乘最后有几个0只需要考虑有几个5就够了,含有5的个数可以直接暴力,因为数据不大,最多才含有100000个5。
AC代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<set>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
using namespace std;
typedef long long ll;
int n, m, k;
int a, b;
ll T, t;
int ans = 0;
string str;
int main()
{
scanf("%d", &m);
n = m;
int num = 0;
for(int i = 5; i <= 500000; i += 5){//因为只有5的倍数可以分解出来5,所以直接+5就好
t = i;
while(t){
if(t % 5 == 0){
t /= 5;
num++; //从开始就统计5的个数
}
else break;
}
if(num >= m)//如果5的个数(相当于末尾0的个数)>= 预期的就进入
{
if(num == m){
puts("5");
up(j, 1, 5) printf("%d%c", i++, j == 5 ? '\n' : ' ');
break;
}
else { //比如5个0结尾的就不存在因为 25 ! 里面6个5 20!里面4个5
//这种现象是由于 25 == 5 * 5 ,一个数分解多个5 造成的
puts("0");
break;
}
}
}
}
数学规律:
数学规律这里作为重点来讲解,思路非常简单,代码非常简洁,速度也快,下面详细说明:
先给出数学公式:
f(x)代表正整数x末尾有f(x)个0
f(x) = | f(n!) = 0 (0 < n < 5)
| f(n!) = k + f(k!) (n >= 5) 其中k = n / 5 向下取整
通俗的证明:
首先通过对刚才暴力规律的理解,相信大家理解了,计算n!的末尾0的个数,就相当于统计n!分解后出现了多少个5,那么n!什么情况下会分解出来5呢,毫无疑问只有n!里是5的倍数的数。例如: 31 ! = 31 * 30 * 29 * 28 * 27 * 26 ...... * 3 * 2 * 1
那么31!末尾有多少个0,就看31!可以分解出来多少个5,看可以分解出来多少个5,就把能分解出5的数提取出来,则就是:
提取出里面5的倍数的数: 30 * 25 * 20 * 15 * 10 * 5 ( 31!里仅有这些数才可以分解出来5)
且 30 * 25 * 20 * 15 * 10 * 5 == 5*6 * 5*5 * 5*4 * 5*3 * 5*2 * 5*1 == 5^6 * 6!
所以31!末尾0的个数为 6 + 1(6!里含有5的个数) == 7个0。
大家观察一下这个 5 ^ 6 * 6 里的6怎么计算出来的呢? 不就是 : 31 / 5 向下取整嘛,至于为什么,不言而喻了~
如果推广到n呢?
n! 末尾含有0的个数(或者说含有5的个数)为: 5^(n/5) * (n/5)! == 5^k * k! == (k个) + (k! 里面含有5的个数)
所以总结出:
f(x)代表正整数x末尾有f(x)个0
f(x) = | f(n!) = 0 (0 < n < 5)
| f(n!) = k + f(k!) (n >= 5) 其中k = n / 5 向下取整
所以直接一个递归就出来某个阶乘末尾有多少个0,有不明白的地方欢迎评论区提问~
其实这个题目是逆过来了,给你末尾0的个数让你求某个数的阶乘,这样可以利用二分来查找,因为结果不可能超过500000,所以速度还是比较快的。
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<sstream>
#include<vector>
#include<map>
#include<set>
#define up(i, x, y) for(int i = x; i <= y; i++)
#define down(i, x, y) for(int i = x; i >= y; i--)
using namespace std;
typedef long long ll;
int n, m, k;
int a, b;
ll T, t;
int ans = 0;
string str;
int f(int n)
{
if(n/5 == 0) return 0;
return n / 5 + f(n / 5);
}
int main()
{
scanf("%d", &n);
int l = 0, r = 500000, mid, flag = 0;
while(l <= r)
{
mid = (l + r) / 2;
t = f(mid);
if(t == n){
puts("5");
while(mid % 5 != 0) mid--;
up(j, 1, 5) printf("%d%c", mid++, j == 5 ? '\n' : ' ');
flag = 1;
break;
}
if(t > n) r = mid - 1;
if(t < n) l = mid + 1;
}
if(flag == 0) puts("0");
}