我们知道,阶乘这玩意一般来说,很大时可以和次方相提并论,所以在计算机中很容易溢出,所以对于它,只能采用高精度求解。
下面我们有两个求法。
一、当所求n不大时,这里限制范围为n在1~1000之间
我们可以采用如下方法:
采用数组逐位解决此问题:
那么我们就要知道这个数有多大,从而来决定开多大的数组。
n的位数可以用log 10(n)+1表示;
故n!的位数可以用log10(n!)+1表示;
log10(n!)=log10(1)+......+log10(n);
这里引用一个数学公式:斯特林公式:n!≈√(2πn) (n/e)n
具体讲解在这里:https://blog.csdn.net/hqzzbh/article/details/79941318
(说明一下由于math.h的头文件内log函数是以e为底的,所以我们在需要一个以其他为底的数前可以除以log该数
如我们需要一个log以2为底的3,那么就是log3/log2就行了,数据类型自己决定咯)
下面贴代码,注释讲解:
#include<stdio.h>
#include<string.h>
#define maxn 3000//通过公式可以求得开3000的数组足够了
int f[maxn];//f数组中每一位只存储一个个位数,故int即可
int main()
{
int n;
scanf("%d", &n);
memset(f, 0, sizeof(f));//开始全部置0
f[0] = 1;
for(int i = 2; i <= n; i++){//阶乘从1开始可以省略,直接从2开始
int c = 0;//表示进位
for(int j = 0; j < maxn; j++){ //由于没那么精确,所有位都走一遍
f[j] = f[j] * i + c;//本位与数相乘加上来自上一位的进位
c = f[j] / 10;//判断并存储本次的进位情况
f[j] = f[j] % 10;//将本位mod10置成个位存储
}
}
int j;
for(j = maxn-1; ; j--)
if(f[j]) break;//由于存储是个位放在0,位权越大对应数组下标越大
//从后向前判断若不是0则遇到最大位,退出
for(int i = j; i >= 0; i--)//从后向前输出
printf("%d", f[i]);
return 0;
}
二、当我们遇到的更大的阶乘该如何?
如最大为10000,实际检测这种方法在大部分评测中都会TLE
故我们可以降低循环次数,一个数组单元存放一个4位数。
当输出的时候遇到不足四位数,可以想到那就是被省略了,那么补上就行了。注意如果是最高位的话,可以直接输出,不用补0.
代码传送门:https://blog.csdn.net/u012773338/article/details/41649511
三、引申问题 搜blog查到的,顺便写下来了。
如何求一个数的末尾0的总和
详解传送门:https://blog.csdn.net/lchSAIL/article/details/53074285
贴个代码:
#include<stdio.h>
int main()
{
int n, sum = 0;
scanf("%d", &n);
while(n){
sum = sum + n / 5;
n = n / 5;
}
printf("%d", sum);
return 0;
}