求N!后面有多少个0

Description

从输入中读取一个数n,求出n!中末尾0的个数。

Input

输入有若干行。第一行上有一个整数m,指明接下来的数字的个数。然后是m行,每一行包含一个确定的正整数n,1<=n<=1000000000。

Output

对输入行中的每一个数据n,输出一行,其内容是n!中末尾0的个数。

Sample Input

3
3
100
1024

Sample Output

0
24
253

思路

10 = 2*5,求出1-n这些数中能够分解出多少个2和多少个5,则选取较小的那个数便是阶乘末尾0的个数。
很显然,能分解出5的个数肯定比2少,那么代码如下:

用ans记录能够分解出5的个数,i从5开始遍历,每次递增5,到n结束。

第一次提交

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<inttypes.h>
using namespace std;
int64_t sumzero(int64_t n)
{
	if(n <= 4) return 0;
	int ans,ans1=0,ans2=0;
	for(int64_t i=5;i<=n;i=i+5){
		int64_t j = i;
		while(j%5==0) {ans2++;j /= 5;}
	}

	return ans2;

}
int main()
{
	int64_t n,m;
	while(cin>>n){
		for(int i=1;i<=n;i++){
			cin>>m;
			cout<<sumzero(m)<<endl;
		}
	}
	return 0;
}

1<=n<=1000000000
但是n太大了,运行超时。

在这里插入图片描述
这样不行必须优化循环,减少时间复杂度。

第二次提交

只看n,n每次整除5,得到的是1-n这些数里面能够提供5的个数
然后再次对n除5,得到的是剩下的数中还能再提供5的个数, 直到 n=0

int ans = 0;
while(n){
	ans += n/5;
	n = n/5;
}

这样时间复杂度为O(log5(n))而不是O(n/5).

#include<iostream>
#include<stdio.h>
#include<stdlib.h>
#include<algorithm>
#include<string.h>
#include<math.h>
#include<inttypes.h>
using namespace std;
int64_t sumzero(int64_t n)
{
	int ans=0;
	//Z = N/5 + N /(5*5) + N/(5*5*5)…..直到N/(5的K次方)等于0
	//公式中 N/5表示不大于N的数中能被5整除的数贡献一个5,N/(5*5)表示不大于N的数中能被25整除的数再贡献一个5
	while(n){
		ans += n/5;
		n = n/5;
	}

	return ans;
}
int main()
{
	int64_t n,m;
	while(cin>>n){
		for(int i=1;i<=n;i++){
			cin>>m;
			cout<<sumzero(m)<<endl;
		}
	}
	return 0;
}

通过这个题,能够学到一点点编程小技巧,计算思维+降低时间复杂度。

发布了97 篇原创文章 · 获赞 101 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/practical_sharp/article/details/104146974