nyoj 954

N!

时间限制: 1000 ms  |  内存限制: 65535 KB
难度: 3
描述

阶乘(Factorial)是一个很有意思的函数,但是不少人都比较怕它。现在这里有一个问题,给定一个N(0<0<1000000000),求N!的二进制表示最低位的1的位置(从右向左数)。

输入
本题有多组测试数据,每组数据一个正整数N(0<0<1000000000),以EOF结束
输出
求N!的二进制表示最低位的1的位置(从右向左数)。一组数据占一行。
样例输入
1
2
3
4
样例输出
1
2
2
4
提示
2! = (2)10 = (10)2,则第一个1是第二位
3! = (6)10 = (110)2,则第一个1是第二位

4! = (24)10 = (11000)2,则第一个1是第四位


解题思路:

在做这个题目之前,先来看一个问题:

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

 首先,最直接的算法当然是直接求出来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] + …

代码如下:

long GetZeroNum(long n)
{
    long num = 0;
        while(n != 0)
        {
            num=num+n/5;
            n=n/5;
        }
    return num;
}

回到这个题目上,这个题目问的是二进制中,最低位1的位置。那么最低位1之后的肯定全为0,现在就是要找到末尾有多少个0。那么我们的想法和上面一样,找有多少个2的倍数。

AC:

#include<iostream>
using namespace std;

typedef long long LL;

int main()
{	
	LL n,sum;
	while(cin>>n)	
	{
		sum = 0;
		while(n)
		{
			sum += n/2;
			n /= 2;
		}
		cout<<sum+1<<endl;
	}
	return 0;
}


你可能感兴趣的:(数学)