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很小的时候,斯特林公式的取值已经十分准确。





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


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


代码如下:


#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;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值