Skip to content
多项式乘法:从分治优化到FFT

本节将简单介绍从平方复杂度到nlogn复杂度的多项式乘法计算


假设我们有多项式A(n)和多项式B(n),要求A(n)B(n)

显然最暴力的就是两重循环的枚举,时间复杂度O(n2)

分治与优化

分治优化下的时间复杂度能达到O(nlog3)

首先对A(n)和B(n)中缺的项补0(让系数为0),方便后续计算

分治的本质是将原问题不断划分为若干个子问题,如何构造这样的关系呢?

A(n)=a0+a1x1+a2x2+...+anxn分为两半

即令:

A0=a0+a1x1+a2x2+...+an2xn2

A1=an2+1+an2+2x1+...+anxn2

显然有: A(n)=A0+A1xn2

B(n)同理,则A(n)B(n)可以表示为:

A0B0+A1B0xn2+A0B1xn2+A1B1x2n2   (1)

显然我们只需要求出A0B0,A1B0,A0B1,A1B1即可代入求出多项式的结果,而其中A和B的规模为原来的一半,并且同样是求多项式乘法

所以我们现在可以递归去求F(A0,B0),F(A1,B0),F(A0,B1),F(A1,B1),base step为n为1时返回系数乘积

但是此时复杂度依然是O(n2)

如何优化呢?

观察(1)式可知我们实际上不需要知道A1B0,A0B1的值,我们只需要知道A1B0+A0B1即可

构造(A0+A1)(B0+B1)=A0B1+A1B0+A0B0+A1B1

A1B0+A0B1=(A0+A1)(B0+B1)(A0B0+A1B1)

所以我们只需要递归求F(A0+A1,B0+B1),F(A0,B0),F(A1,B1)

此时复杂度为O(nlog3)

快速傅里叶变换

快速傅里叶变换(FFT)的时间复杂度为O(nlogn)

对于一个n阶多项式,我们只需要n+1个点便可以确定(证明: 范德蒙特行列式)

所以要计算两个n阶多项式乘法f(x),g(x),我们只需要在f(x)和g(x)上找2n+1个点,然后相乘即可表示出多项式乘法的结果

如果我们知道多项式f(x)的点值,也知道g(x)的点值,那么我们就可以通过O(1)计算出f(x)和g(x)的乘积多项式的点值

所以如果我们能以较低的时间复杂度内将系数表示法转化为点值表示法,再将点值表示法转回系数表示法,就能以较低的时间复杂度计算多项式的乘法

系数转点值

与分治优化类似,我们同样需要构造递归关系,但是FFT的构造关系与分治不同,我们需要构造一些偶函数的性质方便后续利用

对于多项式f(x)=a0+a1x2+a2x3+...+anxn

我们可以拆分奇偶

f(x)=(a0+a2x2+...+an1xn1)+(a1+a3x2+...+an1xn1)x

现在奇偶的系数都间隔为2,即[0,2,4,...,n1],无法点值表示,我们可以传入x2使得系数间隔为1,即[0,1,2,...,n12],此时可以点值表示

所以:

f(x)=F0(x2)+F1(x2)x

现在我们发现F0F1不也是一样的多项式吗,所以我们可以递归下去,直到系数为0

如何利用单位根的性质呢?

首先我们可以回忆一下单位根的性质

为了方便书写,我们用ωnk表示n次单位根:

ei2πNkn=ωNnk

此时有:

ωnk=ωcnckωnk=ωnk+n2ωn0=ωnn=1

因此:

f(x)=F0(x2)+F1(x2)xf(ωnk)=F0(ωn2k)+F1(ωn2k)ωnkf(ωnk)=F0(ωn2k)+F1(ωn2k)ωnk

你可能会疑问但是这样递归下去依然没有减少计算量啊?

别忘了我们这里F1,F0都满足g(x)=g(x)

同时这里还有个最重要的性质没用到:

ωnk=ωnk+n2

所以

f(ωnk+n2)=F0(ωn2k)F1(ωn2k)ωnk

所以现在我们只需要计算一半的点即可得到F0(ωn2k),F1(ωn2k),然后相加即为前一半,相减即为后一半,这样计算量减半

所以如果我们知道对于点[ωn21,ωn22,ωn23,...,ωn2n]对应的F0,F1点值,我们就可以快速计算出f(ωnk)的点值表达式

如何计算?还记得我们上面说的吗,递归即可

由此每次递归我们都会将子问题的计算规模减半,显然此时的复杂度即为O(nlogn)

点值转系数

在得到点值表达式后,我们可以通过FFT的逆变换得到系数表达式

我们先从DFT的逆变换IDFT开始推导

还记得DFT公式吗?

X[k]=n=0N1x[n]ei2πNkn

我们可以把DFT公式视为矩阵乘法:

[11111ωN1ωN2ωNN11ωN2ωN4ωN2(N1)1ωNN1ωN2(N1)ωN(N1)2]  [a0a1a2aN1]=[p0p1p2pN1]

其中[a0a1a2aN1] 为系数表达式,[p0p1p2pN1] 为点值表达式

所以如果我们要求系数表达式,只需要求原来的逆矩阵即可

注意到:

[11111ωN1ωN2ωNN11ωN2ωN4ωN2(N1)1ωNN1ωN2(N1)ωN(N1)2]T=1N[11111(ωN1)1(ωN2)1(ωNN1)11(ωN2)1(ωN4)1(ωN2(N1))11(ωNN1)1(ωN2(N1))1(ωN(N1)2)1]

综上则有:

X[k]=n=0N1x[n]ei2πNkn

所以将一个多项式在分治的过程中乘上的单位根变为其共轭复数,分治完的每一项除以n即可得到原多项式的每一项系数