ACM_数论_阶乘N!的末尾有几个零 和 末尾有多少个 1 nyoj 954
2014-04-26 08:23
288 查看
原文地址
首先阶乘的一个常识要知道就是25!的末尾6位全是0;
前言:
《编程之美》这本书,爱不释手!
问题描述:
给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=362800,N!的末尾有两个0;
求N!的二进制表示中最低位1的位置。
问题1的求解:
分析:
解法一:
首先,最直接的算法当然是直接求出来N!然后看末尾有几个0就行了。但这里存在两个问题:
(1)不管使用long或者double一定会产生溢出。
(2)效率低下。
对于问题(1),我们可以采用字符串存储的办法解决,但问题(2)是由本身算法决定的,所以只能采用其他的算法。
那
到底有没有更好的算法呢?我们来分析,N!能产生0的质数组合只能是2 *
5,也就是说当对N!进行质数分解之后,N!末尾0的个位M取决于2的个数X和5的个数Y的最小值,即M =
min(X,Y)。又因为能被2整除的数出现的频率比能被5整除的数高得多,且出现一个5的时,最少会同时出现一个2,所以M =
Y。即得出Y的值就可以得到N!末尾0的个数。
计算Y,最直接的方法,就是计算机1…N的因式分解中5的个数,然后求和。
代码如下:
解法二:
那 么还有没有更简单点的方法呢?我们想,Y还能怎么样得到?举个例子 25的阶乘中,总共有6个五,其中5,10,15,20,各贡献一个,25贡献两个,也可以说成,5,10,15,20,25各贡献一个,25又额外贡献 一个,即5的倍数各贡献一个5,25的倍数各贡献一个5,即Y=[25/5] + [25/25]。同理,125中,5的倍数各贡献一个5,25的倍数各贡献一个5,125的倍数也各贡献一个5,所以Y=[125/5] + [125/25] + [125/125],所以可得公式:
Y = [N/5] + [N/52] + [N/53] + …
代码如下:
问题2的求解:
分析:
首先我们来分析一个二进制数乘以2和除以2的过程和结果是怎么样。
一个二进制数乘以2就是把将此二进制数向左移一位,末位补零。除以2时,则要判断末位是否为0,若为0,向右移一位,若不能为0,则不能被2整除。
所以,其实本问题其实是求N!含有多少个2,最低位1的位置等于N!中含有2的个数加1。
代码如下:
首先阶乘的一个常识要知道就是25!的末尾6位全是0;
前言:
《编程之美》这本书,爱不释手!
问题描述:
给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=362800,N!的末尾有两个0;
求N!的二进制表示中最低位1的位置。
问题1的求解:
分析:
解法一:
首先,最直接的算法当然是直接求出来N!然后看末尾有几个0就行了。但这里存在两个问题:
(1)不管使用long或者double一定会产生溢出。
(2)效率低下。
对于问题(1),我们可以采用字符串存储的办法解决,但问题(2)是由本身算法决定的,所以只能采用其他的算法。
那
到底有没有更好的算法呢?我们来分析,N!能产生0的质数组合只能是2 *
5,也就是说当对N!进行质数分解之后,N!末尾0的个位M取决于2的个数X和5的个数Y的最小值,即M =
min(X,Y)。又因为能被2整除的数出现的频率比能被5整除的数高得多,且出现一个5的时,最少会同时出现一个2,所以M =
Y。即得出Y的值就可以得到N!末尾0的个数。
计算Y,最直接的方法,就是计算机1…N的因式分解中5的个数,然后求和。
代码如下:
static long GetZeroNum(long n) { long num = 0; int i,j; for(i=1; i<=n; i++) { j=i; while(j % 5 == 0) { num++; j/=5; } } return num; }
解法二:
那 么还有没有更简单点的方法呢?我们想,Y还能怎么样得到?举个例子 25的阶乘中,总共有6个五,其中5,10,15,20,各贡献一个,25贡献两个,也可以说成,5,10,15,20,25各贡献一个,25又额外贡献 一个,即5的倍数各贡献一个5,25的倍数各贡献一个5,即Y=[25/5] + [25/25]。同理,125中,5的倍数各贡献一个5,25的倍数各贡献一个5,125的倍数也各贡献一个5,所以Y=[125/5] + [125/25] + [125/125],所以可得公式:
Y = [N/5] + [N/52] + [N/53] + …
代码如下:
static long GetZeroNum(long n) { long num = 0; while(n != 0) { num=num+n/5; n=n/5; } return num; }
问题2的求解:
分析:
首先我们来分析一个二进制数乘以2和除以2的过程和结果是怎么样。
一个二进制数乘以2就是把将此二进制数向左移一位,末位补零。除以2时,则要判断末位是否为0,若为0,向右移一位,若不能为0,则不能被2整除。
所以,其实本问题其实是求N!含有多少个2,最低位1的位置等于N!中含有2的个数加1。
代码如下:
//计算n的阶乘的二进制中最低位1的位置, //返回值表示倒数第几位; static long LowestOnew(long n) { long num=0; while(n!=0) { num=num+n/2; n=n/2; } return num+1; }
相关文章推荐
- ACM_数论_阶乘N!的末尾有几个零
- (ACM数论)求N的阶乘末尾有多少个0
- NYOJ 954 求N!二进制末尾几个0
- hdu 1124 Factorial 数论,就是求一个数的阶乘的结果末尾有多少0.
- CF633 B 数论 阶乘末尾有几个0 二分
- ACM-大数阶乘末尾零的个数
- 100 的阶乘末尾有多少个0?
- N的阶乘末尾有多少个0
- N的阶乘(N!)中的末尾有多少个0?
- C++中求100的阶乘的末尾包含多少个0?
- n的阶乘(n!)末尾有多少个0
- 用十进制计算30!(30的阶乘),将结果转化成3进制进行表示的话,该进制下的结果末尾会有多少个0?
- 找出n的阶乘末尾有几个零
- 怎么判断N!的阶乘末尾有几个零
- 100的阶乘末尾有多少个零?
- java语言学习之n的阶乘末尾有多少个0
- N的阶乘(N!)中的末尾有多少个0?
- 求一个阶乘n!的结果末尾有几个零
- uva 10061 How many zero's and how many digits ?(不同进制阶乘末尾几个0)+poj 1401
- 给定一个整数N,那么N的阶乘N!末尾有多少个0呢