我们知道,阶乘这玩意一般来说,很大时可以和次方相提并论,所以在计算机中很容易溢出,所以对于它,只能采用高精度求解。

下面我们有两个求法。

一、当所求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;
}