POJ上有这个题目。http://poj.org/problem?id=1401。去掉一大堆没有用的信息,POJ的描述如下:

For example, they defined the function Z. For any positive integer N, Z(N) is the number of zeros at the end of the decimal form of number N!. They noticed that this function never decreases. If we have two numbers N1 < N2, then Z(N1) <= Z(N2). It is because we can never "lose" any trailing zero by multiplying by any positive number. We can only get new and new zeros. The function Z is very interesting, so we need a computer program that can determine its value efficiently.

大概意思就是求N!的末尾0的个数。比如:5! = 120;则末尾0的个数为1.

呵呵,这个题目还不简单么。看初中生的解法:

#include<stdio.h> int factorial(int n)//求n! { int i = 1, result = 1; for(i=1; i<=n; ++i) result *= i; return result; } int numOfZero(int n)//求n!末尾的0的个数 { int num = 0; while(n) { if(0 == n%10) { num++; } n /= 10; } return num; } int main() { int n; while(scanf("%d", &n) != EOF) { printf("%d/n", numOfZero(factorial(n))); } return 0; }

呵呵,代码写完了,那就测试呗。下面是我给的测试数据:

0
0

1
0

2
0

3
0

4
0

5
1

6
1

7
2

8
2

9
1

10
2

11
2

12
4

13
2

14
1

15
4

100

0

这下不对了。发现两个问题:①数据7!末尾的0的个数和9!阶乘末尾0的个数比较,明显有一个是不对的。因为阶乘大的数末尾0的个数肯定大于或等于阶乘数小的数。②100!怎么输出0了啊。

为了解决上面的两个问题。于是,用计算器计算出了7!=5040。这下明白了,7!输出两个2。因为它把不是末尾的0也输出来了。这个好办。只要把numOfZero函数改一下就行,如下:

int numOfZero(int n) { int num = 0; while(n) { if(0 == n%10) { num++; } else//当末尾不为0时退出 { break; } n /= 10; } return num; }

呵呵,一改,7!末尾的0的个数终于正确输出1了。接下来解决100!为什么输出0.还是那样,先用计算器计算一下100! = 9.3326215443944152681699238856267e+157.这下应该想出问题出在哪里了。100!超出了int。不信的话,我们把100!在上面写的factorial(int n)中打印出来,发现100! = 0。这肯定不对吧。所以,转而想到一种高中生的解法。那就是用高精度模拟出n!,再计算末尾0的个数。为了清楚的看到高精度模拟出来的结果,干脆把n!打印出来算了。代码如下:

#include<stdio.h> #include<string.h> const int MAX = 1000000; int a[MAX], len; void factorial(int n) { int i, j, carry; a[0] = 1;//储存 0! == 1! == 1; for(i=2; i<=n; ++i) { carry = 0; for(j=0; j<=len; ++j) { a[j] = a[j]*i + carry; carry = a[j] / 10; a[j] %= 10; if((j==len) && (0!=carry))//如果最后一位有进位,位数加1 { len++; } } } } int numOfZero() { int num = 0, i; for(i=0; i<len; ++i) { if(0==a[i]) { num++; } else { break; } } return num; } int main() { int n, i; while(scanf("%d", &n) != EOF) { len = 0; memset(a, 0, sizeof(a)); factorial(n); printf("%d!=",n); for(i=len; i>=0; --i) { printf("%d", a[i]); } printf("/n"); printf("The num of ZEROs = %d/n/n", numOfZero()); } return 0; } /*********************测试数据************************* 10 10!=3628800 The num of ZEROs = 2 20 20!=2432902008176640000 The num of ZEROs = 4 5 5!=120 The num of ZEROs = 1 100 100!=933262154439441526816992388562667004907159682643816214685929638952175999932 29915608941463976156518286253697920827223758251185210916864000000000000000000000 000 The num of ZEROs = 24 *********************测试数据*************************/

呵呵。这下高兴了吧……终于把100!末尾的0的个数算出来了……慢,==,偶再回去看了那个题目,题目的数据量为1 <= N <= 1000000000。不要去数1000000000到底有几个0了,数据量最大为10亿。根据这个算法。单把那个高精度算出来,至少要个10亿个以上的char型数组,至少得循环10亿次以上。这个无论是在空间上,还是在时间上,显然是不可能的。当然,空间上嘛,还是可以解决的。反正题目只要n!后面末尾的0嘛,开一个int a[10]的数组就足够了(10的来由 是100000000后面0的个数加1)。一遇到0,num++,数组里面的数全部往前面移一位偶觉得应该是可以的。但时间上还是得至少循环n遍。所以,得用大学生的解法来解这个题目了。

偶先澄清一下,这个大学生的解法不是偶自己想出来的,是在《编程之美》上看到的。下面就把《编程之美》上的方法写出来。

/*********************以下思想来自《编程之美》***********************/

如果N! == K×10M, ( 0 != k%10 ),那么,M就是要求的。我们把N!进行质因数分解,则有 N! == 2X * 3Y * 5Z……,而10是怎么来的呢,分解之后不就只能由2×5来么。也就是说,只要求分解后的min(x, z),又显然,分解之后2的个数显然要比5的个数多。所以,M == Z了。根据分析,要计算 Z,最直接的方法,就是计算i(i =1, 2, …, N)的因式分解中5 的指数,然后求和。

好吧,那就看代码。

for(i = 1; i <= n; i++) { int num = 0;temp = i; while(temp % 5 ==0) { num++; temp /= 5; } }

评价一下这个代码,这个肯定是不要从1开始循环的,只有5的倍数才能够被5整除,所以,偶把这个代码稍微修改了一下:

int numOfZero(int n) { int num = 0, i, temp; for(i=5; i<=n; i+=5) { temp = i; while(0 == temp%5) { temp /= 5; num++; } } return num; }

呵呵,可不要小看这个改动,如果是10亿次运算,立马降低到2亿。显然。这个还是不符合POJ那个题目的要求的。要运行2亿次。肯定超时。所以还需要改进。把时间复杂度降下来!

啥也不说了,直接把编程之美的第二种思路copy过来了……这才是真正的大学生的解法啊!

公式:Z = [N/5] +[N/52] +[N/53] + …(不用担心这会是一个无穷的运算,因为总存在一个K,使得5K > N,[N/5K]=0。)
公式中,[N/5]表示不大于N 的数中5 的倍数贡献一个5,[N/52]表示不大于N 的数中52的倍数再贡献一个5,……那偶啥也不说了,直接按照他的思路写代码吧:

int numOfZero(int n) { int num = 0, i; for(i=5; i<=n; i*=5) { num += n/i; } return num; }

好了……这个题目到此为止就圆满解决了。输入10亿刷的一下结果就出来了……要有多快就有多快,而且空间复杂度为O(1)。

好了~~~不要到此就以为结束了。《编程之美》还提了一个问题:求N!的二进制表示中最低位1的位置。这个就留给大家自己去思考了。

其实关于大数阶乘的问题还没完。偶在搜索这个问题的相关知识的时候,遇到了关于大数阶乘的两个问题。

①求n!一共有多少位。比如,10! == 3628800.那么有7位。

②求n!后面第一个非零的数。比如10!后面第一个非零数为8。

好了,这两个问题和《编程之美》的第二个问题就留给我以后再补充吧,偶现在要看网页设计方面的知识去了。

求阶乘N!末尾0的个数相关推荐

  1. java n%9==0_用C++实现求N!中末尾0的个数的方法详解

    题目描述: 输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2 输入描述: 输入为1行,n(1≤n≤1000) 输出描述: 输出一个整数 ...

  2. 判断N!阶乘中末尾0的个数

    如果我们要判断出0的个数,如果我们直接求N!那么数据会很大,数据可能溢出, 那么为了得到0的个数我们知道可以从10的角度进行判断,如果我们知道N!中10的个数, 我们就可以判断出0的个数, 如果N!= ...

  3. 求表达式 f(n)结果末尾0的个数

    输入一个自然数n,求表达式 f(n) = 1!*2!*3!*.....*n! 的结果末尾有几个连续的0? 输入描述: 自然数n 输出描述: f(n)末尾连续的0的个数 输入例子1: 11 输出例子1: ...

  4. c语言 n阶阶乘尾0个数,计算n的阶乘(n!)末尾0的个数

    题目: 给定一个正整数n,请计算n的阶乘n!末尾所含有"0"的个数. 举例: 5!=120,其末尾所含有的"0"的个数为1: 10!= 3628800,其末尾所 ...

  5. 求n的阶乘末尾0的个数

    输入一个正整数n,求n!(即阶乘)末尾有多少个0? 比如: n = 10; n! = 3628800,所以答案为2. 思路:末尾0的个数就是指这个数总共有几个10因子,而10又能表示成2和5的乘积.假 ...

  6. 阶乘末尾 0 的个数

    整数区间内整数的因子的个数 如求 100 的阶乘末尾 0 的个数: 思路:一个数 n 的阶乘末尾有多少个 0 取决于从 1 到 n 的各个数的因子中 2 和 5 的个数((2, 5) 构成的对的个数) ...

  7. 阶乘末尾0的个数(java)

    从输入中读取一个数n,求出n!中末尾0的个数. 输入格式: 输入有若干行.第一行上有一个整数m,指明接下来的数字的个数.然后是m行,每一行包含一个确定的正整数n,1<=n<=1000000 ...

  8. C++版本计算n阶乘末尾0的个数原理讲解及代码实现

    C++版本计算n阶乘末尾0的个数原理讲解及代码实现 /*! * Copyright (c) 2020,ZYF. * All Rights Reserved. * * \file Factorial.c ...

  9. 牛客小白月赛6 水题 求n!在m进制下末尾0的个数 数论

    链接:https://www.nowcoder.com/acm/contest/135/C 来源:牛客网 题目描述 其中,f(1)=1;f(2)=1;Z皇后的方案数:即在Z×Z的棋盘上放置Z个皇后,使 ...

最新文章

  1. 仿QQ空间用一个tableview显示多种自定义cell
  2. Linux防止ARP攻击的一些方法
  3. python sum函数numpy_如何用numba加速python?
  4. android代码旋转屏幕,Android Activity源码分析--windowmanager屏幕旋转研究
  5. LeetCode MySQL 1270. 向公司CEO汇报工作的所有人
  6. CVPR 2019 | 旷视提出超分辨率新方法Meta-SR:单一模型实现任意缩放因子
  7. mysql between 等于_MySQL中BETWEEN子句的用法详解
  8. 环形队列的输出_Java数据结构:使用数组实现环形队列详解
  9. dd for windows
  10. cPanel附加域名出现Error from park wrapper: 使用带以下 IP 的命名服务器:
  11. 运维必读:避免故障、拒绝背锅的 10 大原则!
  12. js里面把密码encode_Python实战案例:这是你见过的最详细的JS加密登录某博
  13. html图片轮播_前端轮播图怎么做?JavaScript来帮你轻松搞定
  14. 代码制作数字流星雨_JS+CSS实现流星雨的动画效果(代码)
  15. JavaWeb开发——JSP技术
  16. 网络图片嗅探工具driftnet
  17. mysql源码解读——内存管理MEM_ROOT
  18. kneighbors()返回值indices、distances详解
  19. attempt_load() got an unexpected keyword argument ‘map_location‘
  20. 使用apache的ZipOutputStream进行zip文件压缩

热门文章

  1. 欧几里得算法/扩展欧几里得算法
  2. 设置 Edge 阅读PDF文档时的背景颜色
  3. 会声会影和pr到底哪个好,2023年要学那个视频剪辑软件好?
  4. 无需客户端下载的方法/天翼云网页下载方法
  5. 哔哩哔哩视频任意倍加速播放方法
  6. 计算机规则英语作文,计算机信息技术(五笔及中英文打字测试试题).doc
  7. 开心网,很开心!!!
  8. 【小白笔记】——AD铺铜设置铜与焊盘、通孔的全连接
  9. Xmanager6 下载地址
  10. go test 初始化--- TestMain的使用