以下只YY算法,c++实现,java大神绕道。。。。。
(1)位数的估计
显然对于大数(比如1000的阶乘)的阶乘我们找不到一个数据类型存放这个数,是在太大啦。。。。
那么现在来估计一下这个数的位数:
估计数n的位数的方法:log10(n)+1;
那么log10(n!)+1=log10(1)+log10(2)+...log10(n)+1,这在计算机中是很容易解决的;
ps:斯特林公式:也可以用它两边取对数求得;
#include<cstdio> #include<cmath> int main() { int n,i; double d; while(scanf("%d",&n)!=EOF) { d=0; for(i=1; i<=n; i++) d+=log10(i); printf("%d\n",(int) d+1); } return 0; }
(2)求解n!的大小
看一个例子1567*12=18804:
我们把前一个数分开为15、67,67*12=804、15*12=180,有下列狮子:
15 67
* 12
-----------------------------
8 04
1 80
-----------------------------
1 88 04
那么,计算n的阶乘的时候,n-1的阶乘肯定是很大的,(n-1)!*n就恰好是一个大数乘以一个小的数字;
比如我们计算0到1000的阶乘,那么计算1000!的阶乘有2568位,这个数就决定数组的要开的大小,开打啦会超时,开小啦不够,我们用一个数组存放阶乘,每一个数组单元存放4位,就可以计算出来啦,详情见代码中的注释吧!
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<string> #define maxs 10000 //数组的设置的大小,不能开太大,这样的话扫描的时间太长会超时,也不能太小。。。。 using namespace std; int a[maxs]; int main() { int n,i,j,y; while(scanf("%d",&n)!=EOF) { memset(a,0,sizeof(a));//把数组全部设置为0 for(i=1,a[maxs-1]=1;i<=n;i++)//数组的高位存放数的低位,把最低位置成1,从1乘到n { y=0;//余数 for(j=maxs-1;j>=0;j--) { a[j]=a[j]*i+y; y=a[j]/10000;//得到乘法之后的结果 a[j]=a[j]%10000;//得到进位 } } for(i=0;i<maxs;i++)//从左到右扫描,第一个不是0的跳出 if(a[i])break; printf("%d",a[i++]);//输出第一个不是0的 for(j=i;j<maxs;j++) printf("%04d",a[j]);//注意中间的数字,比如12,由于在数的中间要输出0012 printf("\n"); } return 0; }