这是给大一第四周出的作业题中的一道,由于没有开例会,所以在这里详细的解释一下,以发到公众号推送上面去XDD 如果有误请多多包涵quq,并且能指出来的话感激不尽。
如果想要学习本题思想解法请阅读全文,如果只是想要代码请直接拉到最后方位置。
1.题目描述
(省略原文一大段)总的来说就是求阶乘后末尾的零的个数。
2.解题思路
正常情况肯定想到的是先直接求阶乘然后取它末尾的零,但这种办法对于小数阶乘还好办,数据如果很大了就完全没有办法;如果是大数阶乘取数组从前往后为0的数目的话用的时间和空间也特别的多,因为要先做一次阶乘然后再取,因此思考后发现可以采用数学的方法来做。
一提到阶乘末尾有零的数首先想到的就是5!=120,而我们也知道一个数一旦末尾有了零,那么它不管乘以任何数,得到的结果都至少含有原来个数的零,而这也是这道题的突破点。因此我们取5为步长,所有的操作都是在5!的基础上进行。可能这时候会有几个问题:(1)为什么不考虑10。因为以10为步长的话,像5,15,25这一类的数字计算起来就很麻烦;(2)为什么不考虑2*5,分开求2和5的公倍数然后相乘。这个办法是可以解决5(2*0+5*1),15(2*0+5*3)之类的问题,但是仔细想想要这样分开实现也是很麻烦的,同时还要考虑2个数各自的取值问题。
因此我们可以得到,凡是阶乘末尾有零的必定是由“由5乘以某个偶数得来的”,所以实际上那些末尾有零的数满足以下要求:阶乘里面的数(如3!里面有1,2,3)有5或5与某个数的乘积(如10,15)。
寻找方法如下:
例如,在100中,有5,10,15,20,25......90,95,100这些数:
而5=5*1;10=5*2;15=5*3;20=5*4.。因此5!里面有1个5,10!里面有2个5(5!和10=2*5里面的5),15!里面有3个5(10!和15=3*5里面的5).......则因此10!末尾有2个零,15!末尾有3个零......
这里有一个分界线,那就是25时,25里面有6个5(20!和25=5*5里面的2个5),因此在25之后的每个数里面都实际上会多加1个5,因此25!末尾有6个零,30!末尾有7个零......据此我们可以知道每当数除以5后的余数仍能再次除以5的话就为一个分界线,每过一次分界线后就要多加余数个5,例如25/5=5,5/5=1,它原本是5个5,所以加1之后就是6个零;50/5=10,10/5=2,它原本是10个5,所以加上2个零后就有12个......
当下一次余数为5的时候,此时为125,为125/5=25,25/5=5,5/5=1,根据上面的“每过一次分界线后就要多加余数个5”可知它的5的个数为25+5+1=31。因此我们可以将这个部分设定为一个循环加上一个除以5的判定。
3.代码
分析清楚过后,我们用代码表示上述的内容即为:
1 count=0;//零的个数
2 t=n/5;//n为输入的数,这一步的作用是求出含有5的个数
3 while (t!=0)//余数比5大
4 {
5 count+=t;//含有t个5就有t个零
6 t/=5;//过一次分界线;如果余数小于5就结束循环
7 }
总的代码:
1#include<stdio.h>
2int main(void)
3{
4 long long int n;//可以求很大的数的阶乘
5 long long int t;
6 printf("请输入数字:\n");
7 scanf("%lld",&n);
8 long long int count = 0;
9 t=n/5;
10 while (t!=0)
11 {
12 count+=t;
13 t/=5;
14 }
15 printf("末尾零的个数为:%lld\n",count);
16 return 0;
17}
运行结果:
这篇花的时间也挺久的。。熟练度还是不高,还要继续努力( ・´ω`・ )