• 51nod1057—N的阶乘—(大数阶乘)


    基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题
     收藏
     关注
    输入N求N的阶乘的准确值。
     
    Input
    输入N(1 <= N <= 10000)
    Output
    输出N的阶乘
    Input示例
    5
    Output示例
    120

    思路:按照乘法运算的规则进行模拟,声明一个数组ans,用来存运算后每一位的值。遍历2到n中的所有的数,每次都用这个数去和ans数组中的每个数相乘,并按乘法规则进位即可。

    普通版代码:
     1 //普通版 
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<string>
     6 #include<cmath>
     7 #include<climits>
     8 #include<algorithm>
     9 #include<stack>
    10 #include<queue>
    11 #define eps 1e-7
    12 #define ll long long
    13 #define inf 0x3f3f3f3f
    14 #define pi 3.141592653589793238462643383279
    15 using namespace std;
    16 int main()
    17 {
    18     int ans[50000],n; //ans数组用来储存结果 
    19     while(cin>>n)
    20     {
    21         memset(ans,0,sizeof(ans));
    22         int cnt = 1,res,carry=0; //cnt用来记录当前最高位是多少 
    23         ans[0] = 1;
    24         for(int i=2; i<=n; ++i) //遍历2-n中所有的数 
    25         {
    26             for(int j=0; j<cnt; ++j) //ans中的每个数都乘上i 
    27             {
    28                 res = ans[j]*i+carry; //这一位乘上 i 并加上上一位的进位数量 
    29                 ans[j] = res%10; //按乘法规则进行进位 
    30                 carry = res/10;
    31             }
    32             while(carry) //如果最高为还能进位,最高为就要加 1,一直循环到不能进位为止 
    33             {
    34                 ans[cnt++] = carry%10;
    35                 carry /= 10;
    36             }
    37         }
    38         for(int i=cnt-1; i>=0; --i) //输出 
    39             printf("%d",ans[i]);
    40         printf("
    ");
    41     }
    42     return 0;
    43 }
    但是,上面的代码还并不足以通过这一题,时间复杂度卡在了时间限制的边缘。我们可以对上面的代码进行一个简单但却精妙的优化。在上面的代码中,ans数组中的每个数仅仅只表示了一位,对于整型变量的范围来说,这显得有些浪费。于是乎,我们可以用ans数组中的每个元素来记录最终答案的多位,这样就可以缩短几倍的时间。
    例如,在接下来的代码中,我用ans中的每个数来记录9位,这表示用1000000000代替10来进行进位操作。最后在输出的过程中,如果ans【i】=0,那我们实际上要输出九个0,因为每个位置记录了9位。

    优化版代码:
     1 //优化版:
     2 #include<iostream>
     3 #include<cstring>
     4 #include<cstdio>
     5 #include<string>
     6 #include<cmath>
     7 #include<climits>
     8 #include<algorithm>
     9 #include<stack>
    10 #include<queue>
    11 #define eps 1e-7
    12 #define ll long long
    13 #define inf 0x3f3f3f3f
    14 #define pi 3.141592653589793238462643383279
    15 const ll MAXN = 1000000000; //用来代替10进位的MAXN 
    16 using namespace std;
    17 int main()
    18 {
    19     ll ans[10000]; //用long long防止数据溢出 
    20     int n;
    21     while(cin>>n)
    22     {
    23         ans[0] = 1;
    24         ll res,carry = 0,cnt = 1;
    25         for(int i=2; i<=n; ++i)
    26         {
    27             for(int j=0; j<cnt; ++j)
    28             {
    29                 res = ans[j]*i + carry;
    30                 ans[j] = res % MAXN; //用MAXN进行进位操作 
    31                 carry = res / MAXN;
    32             }
    33             while(carry)
    34             {
    35                 ans[cnt++] = carry;
    36                 carry = 0;
    37             }
    38         }
    39         printf("%lld",ans[cnt-1]); //首先输出最高位的元素,因为最高位的元素并不一定有9位 
    40         for(int i=cnt-2; i>=0; --i) //格式化输出剩下的元素 
    41             printf("%.9lld",ans[i]); // %.9的作用是如果数据大于9位,则正常输出,否则,不足9位将在高为上补 0
    42         //如:%.3输出12,将会输出012,所以,上面的ans[i]中若位0,将输出000000000,防止位数丢失 
    43         cout<<endl;
    44     }
    45     return 0;
    46 }
    
    

    当然,并不一定要用9位来进行记录,在确保不会导致long long数据溢出的情况下,也可以稍微比9大一些。

    如果你选择用15位来记录,运算10000的阶乘时很有可能会溢出,因为15+4=19位,将会超过long long的范围。所以在不太确定的情况下,尽量使用较为保险的长度。

  • 相关阅读:
    生成树
    如何自定义百度网盘分享密码
    斯特林数入门
    各种反演难题训练集合
    LOJ[6247]九个太阳
    min25筛入门
    2020 Petrozavodsk Winter Camp, Jagiellonian U Contest-A-Bags of Candies
    ICPC WF 2018 C Conquer the World 征服世界
    dsu on tree
    生成函数入门级内容
  • 原文地址:https://www.cnblogs.com/tuyang1129/p/9341025.html
Copyright © 2020-2023  润新知