Time Limit: 1000MS |
| Memory Limit: 65536K |
Total Submissions: 27261 |
| Accepted: 8703 |
Description
Input
Output
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;
}