信息学奥赛实战:高精度乘法算法解析与优化技巧

1. 从竖式乘法到代码:高精度乘法的核心思想

在信息学奥赛的赛场上,我们常常会遇到一些“不讲武德”的题目,它们给出的数字大到离谱,动辄上百位,甚至上千位。比如经典的 ybt 13071174,一个要求计算两个100位数的乘积,另一个更是要求计算两个200位数的乘积。这时候,C++里自带的 intlong long 这些数据类型就彻底“歇菜”了,因为它们能表示的范围有限。这就好比让你用一个小茶杯去装下一个游泳池的水,根本不可能。为了解决这个问题,我们就必须请出今天的主角——高精度乘法

高精度乘法的核心思想其实特别朴素,就是我们小学二年级就学过的竖式乘法。你还记得怎么算 123 × 456 吗?我们会把 456 的每一位(6,5,4)分别去乘 123,得到三个部分积,然后再把这些部分积错位相加。高精度乘法在计算机里的实现,就是把这个过程完全模拟出来。

不过,在计算机里,我们不能直接用“数”来存,因为存不下。我们得用数组来存。一个很自然的想法是:把数字的每一位(个位、十位、百位……)分别存到数组的一个元素里。为了方便计算进位,我们通常会把个位存在数组下标为1的位置,十位存在下标2的位置,以此类推。数组的第0个元素(a[0])则用来记录这个数字的总位数。这种存储方式被称为倒序存储,它让进位操作变得像在数组末尾添加元素一样简单直接。

我刚开始学的时候,总觉得把个位放前面有点反直觉,但用几次就发现真香。比如计算 123 + 456,个位对齐就是 a[1]b[1] 相加,进位直接加到 a[2] 上,逻辑非常清晰。如果正着存,处理进位时数组元素的移动会非常麻烦。所以,记住这个“反着存”的小技巧,是高精度算法的第一课。

2. 手把手实现:数组版本的高精度乘法

理论说再多,不如一行代码。我们直接来看如何用数组实现高精度乘法。我会用一个具体的例子,123 × 45,来一步步拆解代码的执行过程,让你看得清清楚楚。

首先,我们把两个数字用字符串读进来,然后转换成倒序存储的数组。a = [3, 2, 1]a[0]=3 表示有3位),b = [5, 4]b[0]=2)。结果数组 r 初始化为全0。

核心的乘法函数是一个双重循环。外层循环遍历乘数 a 的每一位(i 从 1 到 a[0]),内层循环遍历被乘数 b 的每一位(j 从 1 到 b[0])。对于每一对 a[i]b[j],它们的乘积应该累加到结果数组的 r[i+j-1] 这个位置上。为什么是 i+j-1?这是由竖式乘法的错位规则决定的。a 的第 i 位(从个位开始数是第i位)与 b 的第 j 位相乘,得到的部分积的个位,最终会落在结果的第 (i+j-1) 位上。

我们来看第一轮循环:i=1a[1]=3,即个位的3),j=1b[1]=5)。3*5=15,累加到 r[1+1-1] 也就是 r[1],现在 r[1]=15。这里 15 已经超过9了,但先不着急处理进位,继续内层循环。j=2b[2]=4),3*4=12,累加到 r[1+2-1]r[2]r[2]=12。内层循环结束,这时才开始处理这一轮产生的进位。我们用一个变量 c 来记录进位,从 r[1] 开始:r[1]=15

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值