深入探究多项式乘法的快速算法
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
深入探究多项式乘法的快速算法
————————————————————————————————作者: ————————————————————————————————日期:
深入探究多项式乘法的快速算法
焦作市第一中学 闵梓轩
一、 高精度、多项式与生成函数
1.1 高精度 在OI 中我们有时会碰到一些问题的必要数值超出64位整形的范围,这个时候我们就需要用到高精度方式存储。而高精度数的思想是进制思想的一个具体体现,出于正常人类的习惯,我们所使用的高精度数都采用10进制,即每一位都表示十进制上的一个数,从0~9,更进一步,为了优化高精度数运算所花费的时间与空间,我们采用了万进制,即每一位存0~9999的数,这样同时优化了程序效率,同时在输出上也没有什么太大的问题(每一位不足1000补0即可)。
当然,我们也可以用三进制、五进制、450进制,8964进制的高精度数,虽然因为在输出时会变得非常麻烦而没有人去用,但是它们的可行性正对应了进制的一种思想,比如一个十进制数12450,它的算数含义是0123410*010*510*410*210*1++++二进制数10010,它的算数含义是142*12*1+(把为0的位忽略),这样形如
),0(*0N a x a x a i i n
i i i ∈<≤∑=的每一位上的数字在数值表示上都乘上了某个数的一个幂的数正是进制思想的基础。在编程实现上这样的一个数我们通常用整形数组来表示,a [i]表示i次项的系数,如果数组长度为n,那么学过高精度的人都知道两个数相加的时间复杂度是θ(n ),两个数相乘的时间复杂度是O(n^2),在信息学竞赛中,这样的时间复杂度足以满足大部分题目的需求,因为一般来说我们的数值都不会达到10^100000次方这么大。
1.2多项式
ﻩ熟悉数学的我们能够发现上面这样的一个式子,如果忽略了括号中的内容的限制,那么我们
可以发现这样的式子其实就是我们所学的n 次多项式∑∞==0*)(i i i x a x A ,比如
十进制数12450就是05421234++++x x x x 当x=10的时候的数值嘛。所以,当一个值b 代入多项式A(x)时,这个式子也就变成了一个值A(b)。但是要注意的是多项式的系数是没有限制的,所以多项式可以用浮点数组表示,而且我们可以惊奇地发现多项式的加法和乘法在代码上除了不需要进位之外和高精度是一样的。所以说,我们所见的b 进制数值,就是一个当x=b的多项式的取值而已。但是在多项式中,x 的意义仅仅是一个符号而已,ai*x^i 你可以理解为ai 在数组的第i 个位置。
我们需要注意的是,n 次多项式的数组表示需要用到n+1个数,为什么?因为有n个含x 的项和一个常数项,所以我们一般把多项式A(x)的最高次项的次数+1称作为这个多项式的次数界(次数界的真正意义是系数不为零的最高次项的次数+1,下文中提到的“次数界“为了更
清晰的算法表述,将其定义为按需求扩展后的数组长度,此时最高次项可能是为零的。)。所以,存储一个次数界为n 的多项式只需要开一个长度为n的数组就行了。
现在我们需要严格地定义多项式的运算,以下假定A 、B 的次数界分别为n 、m:
∑∑∑∑∑-==--==+-====+=
+=22002
2010)(,那么)()()(D 定义)()(,那么)()()(定义n k k i k i
k i n k k k j i j i n i i i i x b a x b a x D x B x A x x b a x C x B x A x C ﻩ注意D的次数界:两个次数界为n 和m 的多项式相乘时,积的次数界为n+m-1,D 被称为A 和B 的卷积。
这样一来求和就是从0到n-1枚举i,将ai 和bi 相加的结果作为ci 即可,时间复杂度θ(m ax(n ,m))。求积就是从0到n-1两层枚举i 和j,将a i和bj 相乘的结果加到d(i+k)上,时间复杂度θ(nm)。说白了就是不用进位的高精度乘法。
1.3 生成函数
然而多项式在OI 中有什么用呢?好像除了高精度之外没有什么卵用。但是熟悉组合数
学的小伙伴们会了解一个叫做生成函数的东西,生成函数是什么呢?是∑∞=0*i i i
x a ,
看到了木有,和多项式简直一模一样,而且如果把∞换成n ,那这个式子不就真的变成多项式了吗?在组合数学中,数列A的生成函数的i 次项系数ai 就是这个数列的第i 项。然而我们在生成函数解决问题时是用得到乘法的,有人可能会说这T M有无穷项你乘个卵?但是我们真正关心的没有那么多项,比如我们可能会只关注这个数列的第n 项,这个时候第n +1项以及往后的数值我们就没有必要再乘了(相当于对x^(n+1)取模,同余原理懂吧?懂吧?就像组合计数时要求你对一个大质数取模避免高精度一样),这个时候,生成函数的乘法就变成了多项式乘法!O(n^2)的乘法或许对于高精度来说足够了,但是对于只需要算常数次乘法,并且只关心其中一项的生成函数来说,你需要计算的,可能有很多位。比如我们需要计算一个一个数列的第n 项,也就是这个数列生成函数的第n 位,那么如果当n=300000的时候你的乘法就会瞬间爆炸,那么,有没有更快的算法呢?
二、分而治之
ﻩ分治思想对于计算机科学而言就像心脏,而数组这样的形式是很容易引起我们的分治欲望的,我们不如来看看是否能够通过对数组进行分治而来实现优化。
2.1 裂项相乘
对于数组来说,最基本的分治就是从中分开了,一般的数组分治就是取左端点右端点加起来除以二省略余数作为分治的界限,但是如果数组的长度正好是偶数的话思路分治算法会更加方便一些,直接从中间分开就行了,两边长度一样的。
我们注意到,生成函数如果只有有限项不为0的话,那么它就是多项式,如果我们反过来想,这个性质就变成了可以通过往多项式最高位后面补0来无限地增加数组的长度。比如我们如果有249个项,可以往最高位补个0来让它变成250个项,这不就容易分治了吗?
那么现在关键是如何分治,数组分治就是把数组分成连续的多份嘛,而由于很多原因(比如基于二进制的位运算常数很小,二分比多分编程实现更容易而且渐进复杂度是一样的)我们通常采用二分,也就是把数组一分为二,此时由于上面的性质我们不妨假设我们所需要面