Problem Description

In many applications very large integers numbers are required. Some of these applications are using keys for secure transmission of data, encryption, etc. In this problem you are given a number, you have to determine the number of digits in the factorial of the number.

Input

Input consists of several lines of integer numbers. The first line contains an integer n, which is the number of cases to be tested, followed by n lines, one integer 1 ≤ n ≤ 107 on each line.

Output

The output contains the number of digits in the factorial of the integers appearing in the input.

Sample Input

2 10 20

Sample Output

7 19

 

 

应用的数学知识:

斯特灵公式是一条用来取n阶乘近似值的数学公式。一般来说,当n很大的时候,n阶乘的计算量十分大,所以斯特灵公式十分好用,而且,即使在

n很小的时候,斯特灵公式的取值已经十分准确。

公式为:.这就是说,对于足够大的整数n,这两个数互为近似值。更加精确地:

或者:

 

由于求一个数的位数个数可用公式:log10N,因此将斯特灵公式两边求对数再进行相应的化解可以得到log10N=n*log10(n/e)+0.5*log10(PI*n*2)+1。。。。。

 

 

所以这道题目其实考的就是单纯的数学公式了大声笑(有点郁闷。。。。。)

 

下面就是代码:

#include<iostream>
#include<string>
#include<iomanip>
#include<cmath>
using namespace std;
#define e 2.718281828

void main()
{
	long n,a,temp;
	int k,j;
	int b[11]={1,1,1,1,2,3,3,4,5,6,7};
	while(cin>>n)
	{
		for(long i=0;i<n;i++)
		{
			cin>>a;
			if(a>10)
			{
				temp=a*log10(a/2.718281828)+0.5*log10(3.14159265*2*a)+1;
				cout<<(int)temp<<"\n";
			}

			else
				cout<<b[a]<<"\n";
		}
	}
}

 

 

 

后来又针对这道题研究了一下如何用字符串实现很大的数字之间的相加、相乘、阶乘等的功能,感觉比较复杂,写了快一天了,唉。。。真是,不过收获还不少。

写下今天写程序的感悟吧:

看了SEG的代码(下面会有程序对比)我发现自己写的程序真的很乱,当碰到那种比较复杂的问题,会比较容易急躁,就想着赶快着手去做,缺少了做题前的构思一步。

所以就算写了,也是错误百出,又要花费大量的时间去调试啥的,一遍一遍地测试,一遍一遍地错,那很打击自信诶~~~~

下面就是SEG的建议,对我比较有用的:

1、写程序前最好打好框架(写好函数名,参数,构思好该函数功能)

2、注意多写写注释,一边以后自己或别人理解。

就犹如写接口,让一些类去继承。还有很重要的一点就是要有耐心,有毅力,写程序真的很考验人的,不只是智商还有心态,坚持下去,不厌其烦地知道得到最终结果。。。

相信自己坚持就是胜利~~~~~~~~~~~

 

 

 

下面是两种版本的代码:

SEG版:

 

#include<iostream>
#include<string>
#include<cmath>
#include<iomanip>
#include "num.h"
using namespace std;
NUM initNum(){
	NUM n;
		n = (char *)malloc(INIT_NUM_SIZE*sizeof(char));
	if(n==NULL)
		exit(0);
	memset(n,0,INIT_NUM_SIZE*sizeof(char));
	return n;
}

void outputNum(NUM n){
	long i;
	for(i=len(n)-1;i>=0;i--)
		cout<<n[i]-48;
	cout<<endl;
}

long len(NUM n)
{
	long i;
	for(i=0;n[i]!=0;i++);
	return i;
}

NUM longToNum(long l){
	int i=0;
	NUM n = initNum();
	while(l>0){
		n[i++] = (l%10)+48;
		l=l/10;
	}
	n[i]=0;
	return n;
}

NUM plus(NUM a,NUM b){
	NUM c = initNum();
	long lena=len(a);
	long lenb=len(b);
	long lenmin=lena<lenb?lena:lenb;
	int i;
	for(i=0;i<lenmin;i++)
	{
		if(c[i]>0)c[i] = c[i]+a[i]+b[i]-48;
		else c[i] = a[i]+b[i];
		if(c[i]>=(2*48+10)){
			if(c[i+1]!=0)
				c[i+1]++;
			else
				c[i+1]=48+1;
			//c[i]为进位(-10)后剩余的数字+48
			c[i]=c[i]-(2*48+10)+48;
		}else{
			//c[i]由两位数字相加,所以会有2个48
			c[i]-=48;
		}
	}
	while(a[i]){
		if(c[i]){
			c[i] = c[i]-48;
			c[i] += a[i];
			if(c[i]>=(48+10)){
				if(c[i+1]!=0)
					c[i+1]++;
				else
					c[i+1] +=(48+1);
				c[i]=c[i]-(48+10)+48;
			}
		}else{
			c[i] = a[i];
		}
		i++;
	}
	while(b[i]){
		if(c[i]){
			c[i] = c[i]-48;
			c[i] += b[i];
			if(c[i]>=(48+10)){
				if(c[i+1]!=0)
					c[i+1]++;
				else
					c[i+1] +=(48+1);
				c[i]=c[i]-(48+10)+48;
			}
		}else{
			c[i] = b[i];
		}
		i++;
	}
	return c;
}

//从a数组的第StaIndOfa位开始与b相加。
//StartIndexOfa从1开始计数
NUM plus(NUM a,NUM b,int StaIndOfa){
	NUM c = initNum();
	long lena=len(a);
	if(a[0]){
		if(StaIndOfa<=0){
			cout<<"错误的StartIndexOfa"<<endl;
			exit(0);
		}
	}
	if(lena<StaIndOfa)
		for(int i=lena;i<StaIndOfa;i++)
			a[i] = 48+0;
	lena=len(a);
	long lenb=len(b);
	long lenmin=(lena-StaIndOfa+1)<lenb?(lena-StaIndOfa+1):lenb;
	int i,j;
	for(j=0;j<StaIndOfa-1;j++)
		c[j] = a[j];
	for(i=StaIndOfa-1;i<lenmin+StaIndOfa-1;i++)
	{
		if(c[i]>0)c[i] = c[i]+a[i]+b[i-StaIndOfa+1]-48;
		else c[i] = a[i]+b[i-StaIndOfa+1];
		if(c[i]>=(2*48+10)){
			if(c[i+1]!=0)
				c[i+1]++;
			else
				c[i+1]=48+1;
			//c[i]为进位(-10)后剩余的数字+48
			c[i]=c[i]-(2*48+10)+48;
		}else{
			//c[i]由两位数字相加,所以会有2个48
			c[i]-=48;
		}
	}
	while(a[i]){
		if(c[i]){
			c[i] = c[i]-48;
			c[i] += a[i];
			if(c[i]>=(48+10)){
				if(c[i+1]!=0)
					c[i+1]++;
				else
					c[i+1] +=(48+1);
				c[i]=c[i]-(48+10)+48;
			}
		}else{
			c[i] = a[i];
		}
		i++;
	}
	while(b[i-StaIndOfa+1]){
		if(c[i]){
			c[i] = c[i]-48;
			c[i] += b[i-StaIndOfa+1];
			if(c[i]>=(48+10)){
				if(c[i+1]!=0)
					c[i+1]++;
				else
					c[i+1] +=(48+1);
				c[i]=c[i]-(48+10)+48;
			}
		}else{
			c[i] = b[i-StaIndOfa+1];
		}
		i++;
	}
	return c;
}
NUM singleMultiply(char a,NUM b){
	NUM c = initNum();
	long i;
	long lenb = len(b);
	for(i=0;i<lenb;i++){
		int reala = a-48;
		int realb = b[i]-48;
		int result = reala*realb;
		if(result>10){
			if(c[i]){
				c[i] += (result%10)+48;
			}else{
				c[i] = (result%10)+48;
			}
			c[i+1] = result/10;
		}else{
			c[i] += result+48;
		}
		if(c[i]>=(10+48)){
			c[i+1] += (c[i]-48)/10;
			c[i] = c[i]-(48+10)+48;
		}
	}
	if(c[i])c[i] += 48;
	if(c[i]>(10+48)){
		c[i+1] = (c[i]-48)/10 + 48;
		c[i] = c[i]-(48+10)+48;
	}
	return c;
}

NUM Multiply(NUM a,NUM b){
	NUM c,sum;
	sum = initNum();
	long lena = len(a);
	for(long i=0;i<lena;i++){
		c = singleMultiply(a[i],b);
		sum = plus(sum,c,i+1);
	}
	return sum;
}

NUM Factorial(NUM a){
	//定义变量阶乘、乘数和1
	NUM jc,cs,one;
	one = jc = cs = initNum();
	one[0] = 48+1;//one代表1
	//for(jc=1,cs=1;cs!=a;cs++)
	for(plus(jc,one),plus(cs,one);strcmp(cs,a)!=0;cs=plus(cs,one)){
		jc = Multiply(jc,cs);
	}
	jc = Multiply(jc,a);
	return jc;
}
void main(){
	cout<<"现在开始测试+操作符"<<endl;
	NUM a,b,c=NULL;
	c = initNum();
	long al,bl;
	cin>>al>>bl;
	a = longToNum(al);
	b = longToNum(bl);
	c = plus(a,b,1);
	outputNum(c);

	cout<<"现在开始测试单数*多数的乘法操作"<<endl;
	cout<<b[0]<<"*"<<al<<"=";
	c = singleMultiply(b[0],a);
	outputNum(c);

	cout<<"现在开始测试乘法操作"<<endl;
	c = Multiply(b,a);
	outputNum(c);

	cout<<"现在开始测试阶乘"<<endl;
	cout<<"现在输出!"<<al<<endl;
	c = Factorial(a);
	outputNum(c);
}

 

 

 

 

LCL版:

#include<iostream>
#include<string>
#include<iomanip>
#include<stdio.h>
#include<cmath>
using namespace std;

int init(char *n){
	if(n==NULL)
		n = (char *)malloc(10000000*sizeof(char));
	if(n==NULL)
		exit(0);
	memset(n,0,sizeof(char));
	return 1;
}

long len(char *a)
{
	long i;
	for(i=0;a[i]!=0;i++);
	return i;
}

char *jia(char *a,char *b)  //返回的是相加后的逆序
{
	char *c;
	long lena=len(a);
	long lenb=len(b);
	long lenmin=lena<lenb?lena:lenb;
	c=(char *)malloc(10000000*(sizeof(char)));
	memset(c,0,10000000*sizeof(char));
		for(int i=0;i<lenmin;i++)
		{
			if(c[i]==0)
				c[i]=a[i]-48+b[i]-48+48;
			else
				c[i]=c[i]-48+a[i]-48+b[i]-48+48;
			if((c[i]-48)>=10)
			{
				if(c[i+1]) //不是空
					c[i+1]++;
				else
					c[i+1]+=(48+1);	//空的
				c[i]=(c[i]-48)%10+48;
			}
		}
		if(lena>lenb)
		{
			for(int i=lenmin;i<lena;i++)
			{
				
				if(c[i]==0)
					c[i]=a[i];
				else
					c[i]=c[i]-48+a[i]-48+48;
				if((c[i]-48)>=10)
				{
					if(c[i+1])
						c[i+1]++;
					else
						c[i+1]+=(48+1);	
					c[i]=(c[i]-48)%10+48;
				}
				
			}
		}
		else if(lena<lenb)
		{
			for(int i=lenmin;i<lenb;i++)
			{
				if(c[i]==0)
					c[i]=b[i];
				else
					c[i]=c[i]-48+b[i]-48+48;
				if((c[i]-48)>=10)
				{
					if(c[i+1])
						c[i+1]++;
					else
						c[i+1]+=(48+1);	
					c[i]=(c[i]-48)%10+48;
				}
			}
		}

		return c;
}


char * betjia(char *a,char *b,long l)
{
	//将b后移l位
	long lenb=len(b);
	char *c;
	c=(char *)malloc(10000000*(sizeof(char)));
	memset(c,0,10000000*sizeof(char));
	for(long i=0;i<lenb;i++)
	{
		c[i+l]=b[i];
	}
	for(long i=0;i<l;i++)
		c[i]='0';
	if(l==0)
		return b;
	return jia(a,c);
}
 char *cheng(char *a,char *b) //a被乘数,b乘数
{
	long lena=len(a);
	long lenb=len(b);
	char *c;
	char *sum;
	sum=(char *)malloc(10000000*(sizeof(char)));
	memset(sum,0,10000000*sizeof(char));
	for(long i=0;i<lenb;i++)  //取出b的第i位
	{
		c=(char *)malloc(10000000*(sizeof(char)));
		memset(c,0,10000000*sizeof(char));
		for(long j=0;j<lena;j++) //依次取出a的每一位与b的第i位相乘
		{ //相乘大于10 
			//int temp=1;
			if(c[j]==0)
			{
				if((b[i]-48)*(a[j]-48)>79)
				{
					//temp=0;
					
					if(c[j+1]==0)
						c[j+1]=(b[i]-48)*(a[j]-48)/10+48;
					else
						c[j+1]=(c[j+1]-48+((b[i]-48)*(a[j]-48))/10)+48;
					c[j]=(b[i]-48)*(a[j]-48)%10+48;
				}
				else
					c[j]=(b[i]-48)*(a[j]-48)+48;
			}
				
			else
			{
				if((c[j]-48+(b[i]-48)*(a[j]-48))>=79)
				{
					//temp=0;
					
					if(c[j+1]==0)
						c[j+1]=(c[j]-48+(b[i]-48)*(a[j]-48))/10+48;
					else
						c[j+1]=(c[j+1]-48+(c[j]-48+(b[i]-48)*(a[j]-48)))/10+48;
					c[j]=(c[j]-48+(b[i]-48)*(a[j]-48))%10+48;
				}
				else
					c[j]=c[j]-48+(b[i]-48)*(a[j]-48)+48;
			}
			if((c[j]-48)>=10)  //进位
			{
				if(c[j+1]==0)
					c[j+1]=(c[j]-48)/10+48;
				else
					c[j+1]=c[j+1]-48+(c[j]-48)/10+48;
				c[j]=(c[j]-48)%10+48;
			}
		}
		//cout<<c<<"\n";
		sum=betjia(sum,c,i);
		//cout<<sum<<"\n";
	}
	return sum;
}

char *nixu(char *a)
{
	long lena=len(a);
	char *b=NULL;
	b= (char *)malloc(10000000*sizeof(char));
	memset(b,0,10000000*sizeof(char));
	for(int i=lena-1;i>=0;i--)
		b[lena-1-i]=a[i];
	return b;

}

char *ltostr(long a)
{
	char *b;
	b= (char *)malloc(10000000*sizeof(char));
	memset(b,0,10000000*sizeof(char));
	for(int i=0;a!=0;i++)
	{
		b[i]=a%10+48;
		a=a/10;
	}
	return b;
}
//n=atol(str.c_str());
void main()
{
	char *a;
	char *result;
	long n,x;
	a=(char *)malloc(10000000*sizeof(char));
	result=(char *)malloc(10000000*sizeof(char));
	while(scanf("%d",&n))
	{
		for(long i=0;i<n;i++)
		{
			getchar();
			cin>>x;
			result="1";
			result=nixu(result);
			for(long j=2;j<=x;j++)
			{
				a=nixu(ltostr(j));
				result=cheng(result,a);
			}
			cout<<result<<"\n";
			cout<<len(result)<<"\n";
		}
		
	}
	
}

经过测试,发现虽然说实现了很大数字的阶乘等,但是当数字很大时电脑就扛不住了。。。。这个嘛,也就木办法了,呵呵~~~~~~~~