POJ 1423 HDOJ 1018 Big Number(数学—求n!的位数,log取底和斯特林公式的应用)

Big Number

Time Limit: 1000MS


Memory Limit: 65536K

Total Submissions: 27261


Accepted: 8703

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 <= m <= 10^7 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


题意:hdoj和poj上这两题是一模一样的,求n!的位数,只不过poj数据严一点,hdoj能过的poj会超时。


题解:先来讲解下怎么判断一个未知的数a的位数。给出公式  a的位数 = (int)log10(a) + 1


再来证明: 假设 10^(x-1) <= a < 10^(x) ,可见 a的位数为 x 位。

        我们再对上式用 log10 取底得 :  x-1 <= log10(a) < x  则 x-1 = (int)log(a)  , x = (int)log10(a) + 1 。

所以: a的位数为 (int)log10(a) + 1 。


知道了上面这一点我们来讲第一种解法,这种解法在HDOJ能过,但在POJ上超时。如下:


我们知道 n! 的位数为 (int)log10(n!) + 1。

    log10(n!) = log10(1*2*3*……*n) = log10(1) + log10(2) + log10(3) + ……+ log10(n)

令   ans =  log10(1) + log10(2) + log10(3) + ……+ log10(n)  所以 n! 的位数 = (int)ans + 1 。


代码如下:

#include<cstdio>
#include<cmath>
int main()
{
	int t,n,i;
	double ans;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ans=0;
		for(i=1;i<=n;++i)
			ans+=log10(i);
		printf("%d\n",(int)ans+1);
	}
	return 0;
} 


这样的做法时间复杂度为 O(n) ,而n的范围特别大,下面我们来找到O(1)的做法,需要学习斯特林公式。


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


POJ 1423 HDOJ 1018 Big Number(数学—求n!的位数,log取底和斯特林公式的应用)_第1张图片


POJ 1423 HDOJ 1018 Big Number(数学—求n!的位数,log取底和斯特林公式的应用)_第2张图片



关于证明参见: 百度百科—斯特林公式  更多关于斯特林公式用法请自行百度


现在知道了斯特林公式,即可以直接对 公式运算结果 取对数就能得到答案。


代码如下:


#include<cstdio>
#include<cstring>
#include<cmath>
#define pi acos(-1.0)
#define e exp(1.0)//exp(x)是求e的x次方 
int main()
{
	int t,n;
	double ans;
	scanf("%d",&t);
	while(t--)
	{
		scanf("%d",&n);
		ans=log10(sqrt(2*pi*n))+n*log10(n/e);
		printf("%d\n",(int)ans+1);
	}
	return 0;
}



你可能感兴趣的:(POJ 1423 HDOJ 1018 Big Number(数学—求n!的位数,log取底和斯特林公式的应用))