高精度算法
高进度算法一共分为666个主题,分别是高精度加法、高精度减法、高精度乘法、高精度除法、高精度开根和压位。
一、高精度加法
现在有一道题目,如下
给你两个整数a和b,请你算出它们的和。
数据范围:1<=a,b<=10^1000。
一看这道题,就感觉是基础的a+ba+ba+b问题,其实不然——数据范围肯定会爆。
那么我们怎么做呢?
我们回顾一下小学时候学的竖式加法。
假设a=145,b=44a=145,b=44a=145,b=44,竖式如下图

其实我们只用从最低位开始加,然后加到最高位就行了。
假设两个加数分别存入aaa和bbb数组,答案存入ccc数组,yyy表示进位,则
ci=(ai+bi+y) mod 10c_i=(a_i+b_i+y)\:mod\:10ci=(ai+bi+y)mod10
y=⌊ai+bi+y10⌋y=\lfloor \frac{a_i+b_i+y}{10}\rfloory=⌊10ai+bi+y⌋
那么就可以直接用一个循环做了。
时间复杂度为O(max(n,m))O(max(n,m))O(max(n,m))。
nnn和mmm分别表示两个数的位数。
二、高精度减法
那么高精度减法是不是也可以用竖式的办法解决呢,答案是对。
假设被减数a=100a=100a=100,减数b=78b=78b=78,竖式如下图

计算过程见右边。
其实我们只要判断一下当前这个位置是否够减,如果够,就减;否则,就加上101010再减,并把前一位减去111。
程序如下:
for(int i=1;i<=n;i++)
{
if(a[i]<b[i])
{
a[i]+=10;
a[i+1]--;
}
c[i]=a[i]-b[i];
}
注意:最后要删除前导000。
那如果a<ba<ba<b,怎么办?
因为a−b=−(b−a)a-b=-(b-a)a−b=−(b−a),而b>ab>ab>a,所以我们只用计算b−ab-ab−a就行了,输出时在前面加个负号。
时间复杂度为O(max(n,m))O(max(n,m))O(max(n,m))。
nnn和mmm分别表示两个数的位数。
三、高精度乘法
上面我们解决了加法和减法,那么乘法是怎么样的呢?
乘法需要细心找规律才能找到。
假设乘数分别是121212和131313,竖式如下图

我们看一下上图,可以发现一个规律:第iii位和第jjj位相乘的结果应该存在第i+j−1i+j-1i+j−1位上。
举例一下:
第111位222乘以第222位111,结果应该放在第222位,因为1+2−1=21+2-1=21+2−1=2。
如果不明白可以看下图:

根据这个规律,我们就可以直接计算出答案,这里就不多说了。
注意:答案要累加进一个数组,因为可能会有i+j−1i+j-1i+j−1重复的情况。
时间复杂度为O(nm)O(nm)O(nm)。
nnn和mmm分别表示两个乘数的位数。
四、高精度除法
高精度除法有两种方法,第一种是二分答案,第二种是利用减法来求。
第一种方法
由于乘法是除法的逆运算,所以我们直接寻找一个数看这个数是否满足乘法运算就行了。
找数的方法很简单,就是二分答案。
如果没学过二分答案,可以自己去网上学一学,以后我会出关于二分答案的内容。
二分答案时,我们只要做乘法就行了。
时间复杂度大概为O(nmloga2)O(nm\log_a^2)O(nmloga2)。
nnn表示被除数的位数,mmm表示除数的位数,aaa表示被除数。
其实复杂度远没有这么多。
第二种方法
我们只用一次一次的用被除数减去除数,直到被减数等于000为止,答案就是次数。
这种时间复杂度很高,应该是O(ab)O(\frac{a}{b})O(ba)
aaa表示被除数,bbb表示除数。
五、高精度开根
高精度怎么开根呢,方法和高精度除法一样,都可以用二分答案来解决。
我们二分答案时,就只用算一下乘法,然后调整位置。
时间复杂度为O(nmloga2)O(n^m\log_a^2)O(nmloga2)。
nnn表示被开方数的位数,mmm表示根指数,aaa表示被开方数。
六、压位
那么有什么方法可以使高精度算法的速度更快呢?
答案是,压位。
假如我们现在要算两个数的加法。
我们可以一次就算555位,这样只用开intintint。
我们可以一次就算121212位,这样只用开longlonglong longlonglong。
那么时间复杂度就变成了O(ab)O(\frac{a}{b})O(ba)。
aaa表示原来的时间复杂度,bbb表示压位的位数。
这样就可以大大的缩短时间了。
2120

被折叠的 条评论
为什么被折叠?



