定义 n!=1*2*3*....*n,则 100!的末尾 0 的个数为
时间: 2024-05-03 07:15:45 浏览: 23
末尾的0的个数实际上就是10的个数,也就是2和5的个数。因为每个偶数都可以分解为2的倍数,因此2的个数肯定比5的个数多,所以我们只需要计算n!中5的个数即可。
在100!中,可以被5整除的数贡献了20个5,即有20个5, 25, 30, 35, ..., 100。但是,25可以被5整除两次,所以还有20/5=4个5需要加上,所以100!末尾0的个数为20+4=24个。
相关问题
n的阶乘定义为n!=1*2*3*……*n 如3!=6 n!通常最后会有很多0,如5!=120 最后有一个0,现在统计n!去除末尾的0后,最后k位是多少
题目中的$b_n$的定义是$n$的阶乘,即$b_n=1*2*3*\cdots*n$。已知$b_3!=6$,$b_5!=120$,而$n!$的末尾会有很多个0,现在我们统计$n!$去除末尾的0之后最后有多少个0。注意到10是由$2*5$得到的,因此我们只需要统计$n!$中2和5的个数,然后取两者的最小值,即为$n!$末尾0的个数。显然2的个数远大于5的个数,因此我们只需要计算$n!$中5的因子个数。依次分别除以5,25,125……,并对每次得到的商进行累加即可。具体来讲,设$f(n)$表示$n!$中5的因子数,则有:
$$f(n)=\left\lfloor \frac{n}{5}\right\rfloor +\left\lfloor\frac{n}{25}\right\rfloor+\left\lfloor\frac{n}{125}\right\rfloor+\cdots$$
现在我们来看一下最后一个问题,即求$n!$除以末尾的0之后最后有多少个非0数字。很明显,这就是要求$n!$除以10之后最后一位非0数的个数,而这个数可以看成是$n!$中质因数2和5的个数之间的最小值。根据之前的计算,$n!$中5的因子数即为$n!$末尾0的个数,那么质因数2的个数又可以通过类似的方法来计算,即
$$g(n)=\left\lfloor \frac{n}{2}\right\rfloor +\left\lfloor\frac{n}{4}\right\rfloor+\left\lfloor\frac{n}{8}\right\rfloor+\cdots$$
综上所述,我们只需要求出$f(n)$和$g(n)$,然后取两者的最小值即可。同时,注意到$f(n)$和$g(n)$都可以用对数的形式表示,具体来讲,有:
$$f(n)=\sum_{i=1}^{\infty}\left\lfloor\frac{n}{5^i}\right\rfloor,\quad g(n)=\sum_{i=1}^{\infty}\left\lfloor\frac{n}{2^i}\right\rfloor$$
求n!(1<=n<=10000),并统计输出n!中数字“0”的个数和n!中末尾“0”的个数。C语言 带注释
#include <stdio.h>
int main()
{
int n, i, j, count1 = 0, count2 = 0;
scanf("%d", &n); // 输入n
int f[10001] = {1}; // 定义一个数组f,用于存储n的阶乘,初始值为1
for(i = 2; i <= n; i++) // 从2开始遍历到n
{
int carry = 0; // 定义进位
for(j = 0; j < 10001; j++) // 遍历f数组
{
int mul = f[j] * i + carry; // 将第j位与i相乘并加上进位,得到当前位的乘积
f[j] = mul % 10; // 将当前位的乘积的个位数存入f数组
carry = mul / 10; // 更新进位
}
}
for(i = 10000; i >= 0; i--) // 从f数组的最高位开始遍历到最低位
{
if(f[i] == 0) // 如果当前位为0
{
count1++; // 统计“0”的个数
}
else // 如果当前位不为0
{
break; // 跳出循环
}
}
for(i = 1; i <= n; i++) // 从1开始遍历到n
{
int num = i; // 将当前数赋值给num
while(num % 5 == 0) // 如果num能被5整除
{
count2++; // 统计末尾“0”的个数
num /= 5; // 将num除以5
}
}
printf("%d\n%d", count1, count2); // 输出“0”的个数和末尾“0”的个数
return 0;
}