高精度阶乘

高精度阶乘其实就是进行了 n 次高精乘以低精,只要高精乘以低精会写,高精度阶乘就没问题。

 

 

那么先说一说高精乘以低精吧。

 

高精乘以低精就是把高精度数的每一位乘以低精度数,然后该位的数就是每一次乘积 mod 10 的余数,而 / 10 得到的数作为进位用的数。(这是在数组中每一个元素只存一位的前提下)

不过关于进位,有必要说一下。是先进位,在相乘,还是先相乘,再进位。在高精度加法中是无所谓的,然而在乘法中就必须分出个先后顺序了。(顿时感觉和线段树区间修改 lazy 标记有点像,也是考虑运算数序的问题)

假设先进位再相乘。比如2895 * 64(假设高精度数是2895)那么先给得数的最后一位进位,进0,然后再5 *64 = 320,留下来0,32记着用作进位,没毛病。下一位,先进位9 + 32 = 41,再用41 * 64 = 2624,留下来4,262记着用作进位,但是答案是185280,第二位是8,发现错了,可见这种方法并不能这么写。

回想一下小学竖式,确实是先把这一位相乘,再加上上一位进的数。

 

其实这两种写法都行,只不过先相乘再进位要有些小运算,没有先进位再相乘直观些。这里就只讲一下先进位再相乘吧。

 

具体的乘法上面已经模拟过了,就不再赘述。我只是想强调一下,得数的位数问题,因为最终的积有多少位,我们并不清楚。这就需要动态更新积的位数了。

理论上是积的位数最多等于乘数的位数之和,然而如果我们每一次都去数一遍乘数的位数之和,就显得有些愚笨了。有一个更简单的方法:假设题中的 n <= 1000,那么每一次相乘,最多增加4位。这时我们可以每一次都让积的位数增加4位,然后再删除前导零,这时得到的位数就是这一次相乘的真实位数了。

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<cstring>
 5 using namespace std;
 6 const int maxn = 1e5 +5;        //打表可知,开这么大时,n 最多能达到26439
 7 int a[maxn], n, len = 0;   
 8 int main()
 9 {
10     scanf("%d", &n);
11     a[0] = 1;
12     for(int i = 2; i <= n; ++i)            
13     {
14         int jinwei = 0;
15         for(int j = 0; j <= len + 4; ++j)        //假设每一次位数都增加4 
16         {
17             a[j] = a[j] *i + jinwei;        //先将这一位相乘,在进位 
18             jinwei = a[j] / 10;
19             a[j] %= 10;
20         }
21         int x = len + 4;
22         while(x > 0 && a[x] == 0) x--;        //删除前导零 
23         len = x;                //得到了真正的位数 
24     }
25     while(a[len] == 0 && len > 0)  len--;    //最后再删除一遍前导零 
26     for(int i = len; i >= 0; --i) printf("%d", a[i]);
27     printf("\n");
28     return 0;
29 }

 

posted @ 2018-03-07 22:24  mrclr  阅读(1500)  评论(4编辑  收藏  举报