hdu1018 - Big Number

来源:互联网 发布:电机软件控制工程师 编辑:程序博客网 时间:2024/05/18 03:50

地址

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!=nlnnn+0.5ln(2πn)
      log10n!=lnn!ln10=nlnnn+0.5ln(2πn)ln10
      m=nlnnn+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.14159265int 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

0 0
原创粉丝点击