码迷,mamicode.com
首页 > 其他好文 > 详细

【编程之美】不要被阶乘吓到

时间:2016-05-03 12:07:58      阅读:195      评论:0      收藏:0      [点我收藏+]

标签:

    阶乘(Factorial)是个很有意思的函数,但是不少人都比较怕它,我们来看看两个与阶乘相关的问题。

    1) 给定一个整数N,那么N的阶乘N!末尾有多少个0呢?例如:N=10,N!=3628800,N!的末尾有两个0。

    2) 求N!的二进制表示中最低位1的位置。

【分析】

    对于问题1有些人碰到这样的题目会想:是不是要完整计算出N!的值?如果溢出怎么办?事实上,如果我们从"哪些数相乘能得到10"这个角度来考虑,问题就变得简单了。

    首先考虑,如果N!=K*10M,且K不能被10整除,那么N!末尾有M个0。再考虑对N!进行质因数分解,N!=2X*3Y*5Z*...,由于10=2*5,所以M只跟X和Z有关,每一对2和5相乘可以得到一个10,于是M=min(X,Z)。不难看出,X大于等于Z,因为能被2整除的数出现的频率比能被5整除的数高得多,所以把公式简化为M=Z。

    对于问题2,要求的是N!中二进制表示中最低位1的位置。例如:给定N=3,N!=6,那么N!的二进制表示(1010)的最低位1在第二位。

    判断最后一个二进制位是否为0:若为0,则将此二进制数右移一位,即为商值;反之,若为1,则说明这个二进制数是奇数,无法被2整除。

    所以,这个问题实际上等同于求N!含有质因数2的个数。即答案等于N!含有质因数2的个数加1。 

1. 问题1的解法一

    要计算Z,最直接的办法,就是计算i(i=1,2,3,...,N)的因式分解中5的指数,然后求和,代码如下:

技术分享
 1 #include <iostream>
 2 using namespace std; 
 3 
 4 int numZero(int n)
 5 {
 6     int ret = 0; 
 7     for (int i = 1; i <= n; i++)
 8     {
 9         int j = i; 
10         while (j % 5 == 0)
11         {
12             ret++; 
13             j /= 5; 
14         }
15     }
16     return ret; 
17 }
18 
19 int main(int argc, char *argv[])
20 {
21     int N; 
22     while (cin >> N)
23     {
24         cout << numZero(N) << endl;
25     }
26     return 0; 
27 }
View Code

2. 问题1的解法二

    公式:Z = [N/5] + [N/52] + [N/53] + ... (不用担心这会是一个无穷的运算,因为总存在一个K,使得5K>N,[N/5K] = 0。)

    公式中,[N/5]表示不大于5的数中5倍数贡献一个5,[N/52]表示不大于N的数中52的倍数再贡献一个5……参考代码如下:

技术分享
 1 #include <iostream>
 2 using namespace std; 
 3 
 4 int numZero(int n)
 5 {
 6     int ret = 0; 
 7     while (n)
 8     {
 9         ret += n / 5; 
10         n /= 5; 
11     }
12     return ret; 
13 }
14 
15 int main(int argc, char *argv[])
16 {
17     int N; 
18     while (cin >> N)
19     {
20         cout << numZero(N) << endl;
21     }
22     return 0; 
23 }
View Code

3. 问题2的解法一

    由于N!中含有质因数2的个数,等于[N/2] + [N/4] + [N/8] + [N/16] + …… 则参考代码如下:

技术分享
 1 #include <iostream>
 2 using namespace std; 
 3 
 4 int lowestOne(int n)
 5 {
 6     int ret = 1; 
 7     while (n)
 8     {
 9         n >>= 1; 
10         ret += n; 
11     }
12     return ret; 
13 }
14 
15 int main(int argc, char *argv[])
16 {
17     int N; 
18     while (cin >> N)
19     {
20         cout << lowestOne(N) << endl;
21     }
22     return 0; 
23 }
View Code

4. 问题2的解法二

    N!含有质因数2的个数,还等于N减去N的二进制表示中1的数目。我们还可以通过这个规律来求解,代码略。

相关题目

    给定整数n,判断它是否为2的方幂。

【解答】参考答案如下:

技术分享
1 n > 0 && (n & (n-1) == 0)
View Code

【编程之美】不要被阶乘吓到

标签:

原文地址:http://www.cnblogs.com/xiaoxxmu/p/5454183.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!