n的阶乘末尾零的个数

n的末尾的零的个数,对于这个问题我们首先可以想到末尾零是怎么来的,很明显,它是由因式中的2*5构成的,n的阶乘的因式中有多个2*5,那么n!末尾就有多少个零,那么问题就变成了求n!中有多少个2*5了,又由于因子2出现的频率要远远大于5出现的频率,进而问题简化成了其n!的因式分解中5的幂数。这里有两种方法,一种O(n^2)的和一种O(log n)的:

先来看一下O(n^2)的吧,这种比较容易理解

这种方法呢就是枚举每一个不大于n的数中5的倍数,然后对每一个倍数进行分解,看里面有多少个5,再把这些倍数分解下的5的个数相加,因为是二重循环,故复杂度高一些,时间上会超出一些题目的时间限制。

代码如下:

#include <cstdio>
using namespace std;
int solve(int n)
{
    int num=0;
    for(int i=5;i<=n;i+=5)
    {
        int j=i;
        while(j%5==0)
        {
            num++;
            j/=5;
        }
    }
    return num;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=-1)
      printf("%d\n",solve(n));
    return 0;
}


另一只O(log n)的算法其实是数论中的东西。

我们知道,对于一个数m,我们要找出不大于m的数中有多少个是5的倍数,那么只需拿m/5即可,商即为5的倍数的数目,所以对于n!来说,我们拿n/5,那么得到的结果就是这n个数中能直接分解出的因子5的个数,但不要忘了,这是直接分解出的因子5,此外,一个数的因子还可能含有25,75,125等等这样的数,同理,我们拿n/25,那么就等得到这n个数中能直接分解出的因子25的个数,每次乘5,乘到大于n结束,把这些因子倍数的数目加起来即为n!中一个可以分解出的5的数目,也就是n!末尾零的数目。

代码如下:

#include <cstdio>
using namespace std;
int solve(int n)
{
    int num=0;
    int t=1;
    while(t<=n)
    {
        t*=5;
        num+=n/t;
    }
    return num;
}
int main()
{
    int n;
    while(scanf("%d",&n)!=-1)
      printf("%d\n",solve(n));
    return 0;
}


 

题目有POJ1401    ZOJ2202

你可能感兴趣的:(n的阶乘末尾零的个数)