地址
http://acm.hdu.edu.cn/showproblem.php?pid=1018
定位
同题不同解
数学推导
分析
此题与hdu1042题目内容相似,都是
n!
问题,考察内容却大相径庭。解法也完全不同。hdu1042,要求打印
n!
的计算结果,输入规模 104 ,时间限制10ms。hdu1018,要求打印
n!
的结果位数,输入规模 107 ,时间限制1ms。
对比发现,hdu1042时间相对充足,主要难点在大数存储;hdu1018时间限制明显,先计算结果再输出位数的朴素思路不能满足题目要求。
虽然此题题目名为“Big Number”,但是解题策略和大数没有丝毫关系。此题为纯粹的数学问题,这里有2种解题思路。
取对数,变乘法为对数加法,时间复杂度 O(n) 。
n!=10m+O(1)
化简得 m+O(1)=log10n!
即 m=⌊log101+log102+…+log10n⌋+1利用Stirling公式,时间复杂度 O(1) 。
n!≈2πn−−−√(ne)n
化简得 lnn!=nlnn−n+0.5ln(2πn)
log10n!=lnn!ln10=nlnn−n+0.5ln(2πn)ln10
即 m=⌊nlnn−n+0.5ln(2πn)ln10⌋+1
解题一
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
int main()
{
int T,n,i;
double sum;
scanf("%d*c",&T);
while(T--)
{
scanf("%d*c",&n);
sum = 0.0;
for(i=1;i<=n;i++)
{
sum += log10(i);
}
printf("%d\n",(int)sum+1);
}
return 0;
}
性能
Exe.Time | Exe.Memory | Code Length | Language |
---|---|---|---|
421MS | 1416K | 341B | c |
解题二
代码
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define PI 3.14159265
int main()
{
int T,n,i;
double len;
scanf("%d*c",&T);
while(T--)
{
scanf("%d*c",&n);
len = (n*log(n)-n+log(2*n*PI)/2.0)/log(10);
printf("%d\n",(int)len+1);
}
return 0;
}
性能
Exe.Time | Exe.Memory | Code Length | Language |
---|---|---|---|
0MS | 1408K | 320B | c |
总结
预估问题规模
通过本题,可以深刻得体会阶乘运算结果位数之多。本题应适合在hdu1042之前做,因为本题就是在做预估问题规模的事情。
在做hdu1042时,我就因为没有缜密得预估存储规模吃了大亏。不预估问题规模,所谓大数大到什么程度还是不知道,模拟十进制能满足吗?不能就要模拟千进制、万进制。
总之,选定正确解题策略的前提是对问题规模的准确预估。
Thanks everyone