牛客小白月赛5-D-阶乘(求n内每个数的阶乘相乘后尾数为0的个数)

题目描述

输入描述:

输入数据共一行,一个正整数n,意义如“问题描述”。

输出描述:

输出一行描述答案:
一个正整数k,表示S的末尾有k个0
示例1

输入

10

输出

7

说明

解题思路:求1~n每个数的阶乘相乘后尾数为0的个数。
AC代码一(365ms):暴力枚举1~n也能过?说明测试数据不大。采用法一可以过:直接统计每个元素包含因子为5的个数。但采用法二会TLE,原因同样是暴力枚举,但每次需要重新计算当前i的因子为5的个数,而法一让很多数可以省去这一步,只当枚举到i为5的倍数才会进入那个while循环,可能超时的原因就出在这里。
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int main(){
 5     int n,num,tmp;LL sum;
 6     while(~scanf("%d",&n)){
 7         sum=0,num=0;//num一开始置0,以后每次累加每个元素包含因子为5的个数即可
 8         for(int i=1;i<=n;++i){//从1枚举到n
 9             tmp=i;//表示当前i!=(i-1)!*i
10             while(tmp%5==0)num++,tmp/=5;//num累加当前i元素包含因子为5的个数
11             sum+=num;//累加i!尾数为0的个数
12         }
13         printf("%lld\n",sum);
14     }
15     return 0;
16 }

AC代码二(78ms):根据法一:求N!尾数有多少个0只需求N内为5的倍数的数包含因子为5的个数总和即可,而此题是求1~n内每个数的阶乘相乘之后尾数为0的个数,因此我们同样枚举N内所有为5的倍数i,每求出i包含因子为5的个数num后,因为i~n(n-i+1个元素)内每个数的阶乘都包含当前i这个元素,所以sum累加num*(n-i+1)即可。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int main(){
 5     LL n,tmp,num,sum;
 6     while(~scanf("%lld",&n)){
 7         sum=0;
 8         for(LL i=5;i<=n;i+=5){
 9             tmp=i;num=0;
10             while(tmp%5==0)num++,tmp/=5;
11             sum+=num*(n-i+1);
12         }
13         printf("%lld\n",sum);
14     }
15     return 0;
16 }

AC代码三(5ms):如果测试数据真的很大为10^9,那么前两个肯定是超时的。因此能否根据法二同样用O(log5n)的时间复杂度计算出尾数为0的个数?根据法二公式:假设我们要计算1!~126!,即n=126,则①126/5=25,说明126!中有25个数是5的倍数;②126/25=5,说明126!中有5个数是25的倍数;③126/125=1,说明126!中有1个数是125的倍数。现对1!~126!按包含因子为5的个数(个数相同为同一组)从小到大分成k=n/i=126/5=25组:(共有k-1组每一组有都有5i(i=1,2,3...)个数的阶乘包含因子为5的个数是相同的,最后一组有(1+n%i)个元素)

j=1--->{5!,6!,7!,8!,9!};//有i=5个元素每个元素包含1个因子5

j=2--->{10!,11!,12!,13!,14!};//有i=5个元素每个元素包含2个因子5

...

j=24-->{120!,121!,122!,123!,124!};//有i=5个元素每个元素包含24个因子5

j=25-->{125!,126!}//有2(1+n%i=1+126%5=1+1=2)个元素每个元素包含25个因子5

以上分组是i=5的情况,其他i值基本和这个一样:由等差数列求和公式可求得1!*...*126!中一共有x=(1+k-1)(k-1)/2*i+k*(1+n%i)(其中k=n/i,i=51,52,53...)个因子5,之后按此公式累加(因子为5的个数)x的值(sum+=x)即可求出1!*...*n!尾数为0的个数sum。

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 typedef long long LL;
 4 int main(){
 5     LL n,sum;
 6     while(~scanf("%lld",&n)){
 7         sum=0;
 8         for(LL i=5;i<=n;i*=5){
 9             LL k=n/i;
10             sum+=k*(k-1)/2*i+k*(1+n%i);
11         }
12         printf("%lld\n",sum);
13     }
14     return 0;
15 }

 

posted @ 2018-08-13 10:22  霜雪千年  阅读(414)  评论(0编辑  收藏  举报