原帖链接:http://www.cnblogs.com/kym/archive/2009/10/05/1578224.html    
    我机器上没有C#的开发环境,所以没法测试作者这个代码的耗时,不过10000的阶乘在5秒内完成,不知道作者的代码是否能达到?我想起前段时间在HDU做的一道ACM题,题目的时限要求是1秒内能计算10000的阶乘(当然这是代码跑在它的服务器的时间)。

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1042

      如果按照飞林沙文章中那种常规的思路,逐位相乘,再对齐相加,缺点很明显,如果n值比较大,运算次数将非常多,必定会超时,1万的阶乘想在1秒内完成肯定无法达成。
   
我的思路是把数据分组,每组上限为9999,最多可容纳2万组,每组4位整数,则可以容纳8万位整数(当然,组数可以随你要计算的n的大小进行调整),利用组与组的错位相乘再相加,可以避免楼主这样逐位进行运算。

代码如下:

  1. #include<iostream> 
  2. #include<stdio.h> 
  3. #include<string> 
  4. #include<iomanip> 
  5. #include<algorithm> 
  6. using namespace std;  
  7. #include "time.h"  
  8.  
  9. const int MAX_GROUPS = 20000;//最多2万组,每组最多4位整数,即最多可容纳8万位整数  
  10. const int MAXN = 9999;//每组的上限值  
  11. const int GROUP_LEN = 4;//每组的最大长度  
  12.  
  13. class BigInteger  
  14. {  
  15. private:  
  16.     int data[MAX_GROUPS];  
  17.     int len;  
  18.     void init()  
  19.     {  
  20.         memset(data,0,sizeof(data));  
  21.     }  
  22. public:  
  23.     BigInteger()  
  24.     {  
  25.         init();  
  26.         len = 0;  
  27.     }  
  28.     BigInteger(const int b);  
  29.     BigInteger(const BigInteger &);  
  30.  
  31.     bool operator > (const BigInteger&)const;  
  32.     BigInteger & operator=(const BigInteger &);  
  33.     BigInteger & add(const BigInteger &);  
  34.     BigInteger & sub(const BigInteger &);  
  35.     BigInteger operator+(const BigInteger &) const;  
  36.     BigInteger operator-(const BigInteger &) const;  
  37.     BigInteger operator*(const BigInteger &) const;  
  38.     BigInteger operator/(const int &) const;  
  39.     void print();  
  40. };  
  41. BigInteger::BigInteger(const int num)  
  42. {  
  43.     int res,tmp = num;  
  44.     len = 0;  
  45.     init();  
  46.     while(tmp > MAXN)  
  47.     {  
  48.         res = tmp - tmp / (MAXN + 1) * (MAXN + 1);  
  49.         tmptmp = tmp / (MAXN + 1);  
  50.         data[len++] = res;  
  51.     }  
  52.     data[len++] = tmp;  
  53. }  
  54. BigInteger::BigInteger(const BigInteger & rhs) : len(rhs.len)  
  55. {  
  56.     int i;  
  57.     init();  
  58.     for(i = 0 ; i < len ; i++)  
  59.     {  
  60.         data[i] = rhs.data[i];  
  61.     }  
  62. }  
  63. bool BigInteger::operator > (const BigInteger &rhs)const  
  64. {  
  65.     int ln;  
  66.     if(len > rhs.len)  
  67.     {  
  68.         return true;  
  69.     }  
  70.     else if(len < rhs.len)  
  71.     {  
  72.         return false;  
  73.     }  
  74.     else if(len == rhs.len)  
  75.     {  
  76.         ln = len - 1;  
  77.         while(data[ln] == rhs.data[ln] && ln >= 0)   
  78.         {  
  79.             ln--;  
  80.         }  
  81.         if(ln >= 0 && data[ln] > rhs.data[ln])   
  82.         {  
  83.             return true;  
  84.         }  
  85.         else   
  86.         {  
  87.             return false;  
  88.         }  
  89.     }  
  90.  
  91. }  
  92.  
  93. BigInteger & BigInteger::operator = (const BigInteger &rhs)  
  94. {  
  95.     init();  
  96.     len = rhs.len;  
  97.     for(int i = 0 ; i < len ; i++)  
  98.     {  
  99.         data[i] = rhs.data[i];  
  100.     }  
  101.     return *this;  
  102. }  
  103. BigInteger& BigInteger::add(const BigInteger &rhs)  
  104. {  
  105.     int i,nLen;  
  106.  
  107.     nLen = rhs.len > len ? rhs.len : len;  
  108.     for(i = 0 ; i < nLen ; i++)  
  109.     {  
  110.         data[i] = data[i] + rhs.data[i];  
  111.         if(data[i] > MAXN)  
  112.         {  
  113.             data[i + 1]++;  
  114.             data[i] = data[i] - MAXN - 1;  
  115.         }  
  116.     }  
  117.     if(data[nLen] != 0)   
  118.     {  
  119.         len = nLen + 1;  
  120.     }  
  121.     else   
  122.     {  
  123.         len = nLen;  
  124.     }  
  125.  
  126.     return *this;  
  127. }  
  128. BigInteger & BigInteger::sub(const BigInteger &rhs)  
  129. {  
  130.     int i,j,nLen;  
  131.     if (len > rhs.len)  
  132.     {  
  133.         for(i = 0 ; i < nLen ; i++)  
  134.         {  
  135.             if(data[i] < rhs.data[i])  
  136.             {  
  137.                 j = i + 1;  
  138.                 while(data[j] == 0) j++;  
  139.                 data[j]--;  
  140.                 --j;  
  141.                 while(j > i)  
  142.                 {  
  143.                     data[j] += MAXN;  
  144.                     --j;  
  145.                 }  
  146.                 data[i] = data[i] + MAXN + 1 - rhs.data[i];  
  147.             }  
  148.             else   
  149.             {  
  150.                 data[i] -rhs.data[i];  
  151.             }  
  152.         }  
  153.         len = nLen;  
  154.         while(data[len - 1] == 0 && len > 1)   
  155.         {  
  156.             --len;      
  157.         }  
  158.     }  
  159.     else if (len == rhs.len)  
  160.     {  
  161.         for(i = 0 ; i < len ; i++)  
  162.         {  
  163.             data[i] -rhs.data[i];  
  164.         }  
  165.         while(data[len - 1] == 0 && len > 1)   
  166.         {  
  167.             --len;      
  168.         }  
  169.     }  
  170.     return *this;  
  171. }  
  172. BigInteger BigInteger::operator+(const BigInteger & n) const   
  173. {  
  174.     BigInteger a = *this;  
  175.     a.add(n);  
  176.     return a;  
  177. }  
  178. BigInteger BigInteger::operator-(const BigInteger & T) const  
  179. {  
  180.     BigInteger b = *this;  
  181.     b.sub(T);  
  182.     return b;  
  183. }  
  184. BigInteger BigInteger::operator * (const BigInteger &rhs) const  
  185. {  
  186.     BigInteger result;  
  187.     int i,j,up;  
  188.     int temp,temp1;  
  189.  
  190.     for(i = 0; i < len; i++)  
  191.     {  
  192.         up = 0;  
  193.         for(j = 0; j < rhs.len; j++)  
  194.         {  
  195.             temp = data[i] * rhs.data[j] + result.data[i + j] + up;  
  196.             if(temp > MAXN)  
  197.             {  
  198.                 temptemp1 = temp - temp / (MAXN + 1) * (MAXN + 1);  
  199.                 up = temp / (MAXN + 1);  
  200.                 result.data[i + j] = temp1;  
  201.             }  
  202.             else   
  203.             {  
  204.                 up = 0;  
  205.                 result.data[i + j] = temp;  
  206.             }  
  207.         }  
  208.         if(up != 0)  
  209.         {  
  210.             result.data[i + j] = up;  
  211.         }  
  212.     }  
  213.     result.len = i + j;  
  214.     while(result.data[result.len - 1] == 0 && result.len > 1) result.len--;  
  215.     return result;  
  216. }  
  217. BigInteger BigInteger::operator/(const int & b) const  
  218. {  
  219.     BigInteger ret;  
  220.     int i,down = 0;  
  221.  
  222.     for(i = len - 1 ; i >= 0 ; i--)  
  223.     {  
  224.         ret.data[i] = (data[i] + down * (MAXN + 1)) / b;  
  225.         down = data[i] + down * (MAXN + 1) - ret.data[i] * b;  
  226.     }  
  227.     ret.len = len;  
  228.     while(ret.data[ret.len - 1] == 0) ret.len--;  
  229.     return ret;  
  230. }  
  231. void BigInteger::print()  
  232. {  
  233.     int i;  
  234.  
  235.     cout << data[len - 1];  
  236.     for(i = len - 2 ; i >= 0 ; i--)  
  237.     {  
  238.         cout.width(GROUP_LEN);  
  239.         cout.fill('0');  
  240.         cout << data[i];  
  241.     }  
  242.     cout << endl;  
  243. }  
  244. int main()  
  245. {    
  246.     clock_t   start,   finish;     
  247.     double     duration;     
  248.     int i,n;  
  249.     BigInteger result,num;  
  250.     scanf("%d",&n);  
  251.     start   =   clock();      
  252.     result = BigInteger(1);  
  253.     for(i = 2;i <= n; ++i)  
  254.     {  
  255.         num = BigInteger(i);  
  256.         resultresult = result * num;  
  257.     }  
  258.     result.print();  
  259.     finish   =   clock();     
  260.     duration   =   (double)(finish   -   start)   /   CLOCKS_PER_SEC;    
  261.     printf(   "%f   seconds\n",   duration   );     
  262.     return 0;  

下面给出测试结果,

  1. 我的机器配置:酷睿双核2.0G,内存3G,  
  2. 计算10000的阶乘,我的机器用时3.312秒,在HDU的服务器上,10000的阶乘用时不到900毫秒。  
  3. 计算12345的阶乘,我的机器用时5.078秒。  
  4. 计算20000的阶乘,我的机器用时13.656秒。 

C/C++确实是会快些的,HDU的这道题目对Java程序的时限是5秒内完成1万的阶乘,但c/c++的时限是1秒,由此可以看出。

大家也可以试试在HDU的服务器上提交下你的代码,看看能否在1秒内通过。

此外,还有2个常见的N!题目,就是N!的尾数0的个数和N!的非零末尾数,有兴趣的同学可以自己看看。