Zero---求N的阶乘结尾0的个数

题目:

                            Zero

                                 Time Limit:1000MS Memory Limit:30000KB

Description 

A long time ago people found the value zero to be very useful. Just think about the romans and many more nations that didn't know the zero. Their number representations couldn't display the zero and that's why they are dead now.
So you've got to understand the overwhelming importance of this beautiful gift of science (or nature ?) and praise the zero. That's what you'll do here.
Find out how many trailing zeros are at the end of n! (n factorial). That's all you have to do, but be careful to write an efficient program, n can be really large. For example,
42! = 1405006117752879898543142606244511569936384000000000
so the answer for n=42 would be 9, since there are nine zeros at the end.

Input 

The first line contains an integer m, the number of test cases. After that follow m lines. Every line represents one testcase, which only contains the integer number n. The value of n will be at least 1 and won't be bigger than 2.000.000.000.

Output 

For each testcase, print a line containing the number of trailing zeros. Do not print whitespace before or after the number.

Sample Input 

4
1
23
42
2000000000

Sample Output 

0
4
9
499999997



拿到这题第一反应肯定是求出N!然后再去求结尾0的个数,但想想可能吗?30的阶乘为265252859812191058636308480000000,可以感受下这个数字,而且这只是30的阶乘。。题目给出的最大数是2.000.000.000,能算不,想想都可怕,还真能算。。。开个数组长度为100000的数组,来保存结果的每一位,像这样的代码:

#include <iostream>
#include <cstring>
using namespace std;
const int MAXN = 100000;

int f[MAXN];

int main()
{
    int n;
    while(cin >> n)
    {
        memset(f,0,sizeof(f));
        f[0] = 1;
        int index;
        int last_index = 0;
        for(int i = 2; i <= n; ++i)
        {
            int c = 0;
            int j;
            for(j = 0; j < MAXN; ++j)
            {
                int temp = f[j] * i + c;
                f[j] = temp % 10;
                c = temp / 10;
                if(c == 0 && j == last_index)
                {
                    break;
                }
            }
            last_index = j;
        }
<span style="white-space:pre">	</span>{
<span style="white-space:pre">		</span>统计0的个数;
<span style="white-space:pre">	</span>}
    }
    return 0;
}
这样就可以得出末尾多少0了吧,你试试,看看你的console黑多长时间,天荒地老!!!言归正传,这条路肯定走不通了,换个方法“

#1:

我们知道阶乘末尾0主要是2和5贡献的(2的倍数都可以分解出2),那么0的个数则取决于2和5的个数,即0的个数=min(2的个数,5的个数),我们知道阶乘分解出2的个数远大于5的个数,那么0的个数其实就取决于5的个数。那接下来就可以很happy的coding了:

        int count = 0;
        for(int i = 5; i <= num; i += 5)
        {
            int temp = i;
            while(temp % 5 == 0)
            {
                ++count;
                temp /= 5;
            }
        }
        cout << count << endl;
    }
时间复杂度简直骤降,但不幸总是会不经意的出现,1000ms的time limit依然超时了。那接下来还能有什么办法,其他的方法是想不出来了,只能优化了。。根据公式 :Z = [N/5] +[N/52] +[N/53] + …+[N/5K],总存在一个K使得右边大于左边。公式中N/5表示不大于N的整数可以分解出5的个数,N/(5*5)表示N中能被25整除的数还可以贡献出一个5,依次类推。例如:30! 30的阶乘中贡献30/5 = 6(25,20,15,10,5)个5,而25还能30/25贡献一个5,因此30的阶乘末尾0的个数为7,有了这个思路,coding就很easy了:

#2:

       int count = 0;
        while(num)
        {
            count += num/5;
            num /= 5;//分母除以5相当于分子*5
        }
        cout << count << endl;
效率有提升了,成功ac。。。



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值