(Tip:如果想真正完全弄懂FFTの本质,建议首先去理解傅里叶变换的物理本质以及DFT,这里只是我为了满足算法竞赛的要求的初步学习总结,其实我还是有点懵的
多项式的系数乘法
给定两个多项式:
A(x)=a0+a1x+⋯+an−1xn−1
B(x)=b0+b1x+⋯+bn−1xn−1
其相乘结果为:
C(x)=c0+c1x+⋯+cn−1x2n−2
不难发现,如果使用纯系数乘法,时间复杂度是 O(n2) 的.
点值乘法
性质1:一个n次多项式可以用n个点来表示,即点值与多项式的系数存在映射关系.
因此我们可以构造 2n−1 个 xi,分别代入求点值 O(n2):
A(x):y0,y1,⋯,y2n−2
B(x):y,0,y,1,⋯,y,2n−2
然后相乘:
C(x):y0y,0,y1y,1,⋯,y2n−2y,2n−2
通过插值转化为系数 O(n2):
C(x):c0,c1,⋯,c2n−2
可以发现,如果使用暴力的做法,代入点值以及插值的时间复杂度依然是 O(n2)
FFT 正变换
通过代入复数单位根及其范围内的k次幂,可以将代入点值这一步简化为 O(nlogn)
首先规定多项式次数 n=2b∈N, 这样我们就可以把复平面上的单位圆进行 n 等分(并满足许多有用的性质),这样就可以得到方程 (cosθ+isinθ)n=1 的 n 个复数根.
为什么呢?我们定义第k个根为 ωkn=cos2πkn+isin2πkn
其满足:ωknωmn=ωk+mn,(ωkn)m=ωkmn
周期性:ωkn=ωk+nn
因此,对于单位根 ωn 进行 n 次自乘,发现还是等于自己.
当然,对于所有的 ωkn 也都是一样,且它们皆不相同,因此方程的 n 个解就是这些.
另外其拥有对称性 ωk+n2n=−ωkn 以及折半性 ω2kn=ωkn2
其中折半性使问题可以递归分治求解
考虑多项式 A(x)=a0+a1x+⋯+an−1xn−1, 提取出其奇偶项:
A1(x)=a0+a2x+⋯+an−2xn2−1
A2(x)=a1+a3x+⋯+an−1xn2−1
则 A(x)=A1(x2)+xA2(x2)
我们将 ωkn 中 k<n2 的部分代入:
A(ωkn)=A1(ω2kn)+ωknA2(ω2kn)=A1(ωkn2)+ωknA2(ωkn2)
再将后半部分复数根代入:
A(ωk+n2n)=A1(ω2k+nn)+ωk+n2nA2(ω2k+nn)=A1(ωkn2)−ωknA2(ωkn2)
我们发现,可以将问题规模为 n 转化为问题规模为 n2, 因此该问题可以递归求解. 每一步递归需要将系数分为奇偶两部分,例如:
step1:(a0,a1,a2,a3,a4,a5,a6,a7)
step2:(a0,a2,a4,a6)(a1,a3,a5,a7)
step3:(a0,a4)(a2,a6)(a1,a5)(a3,a7)
到达递归底部时,直接return.
递归执行完两部分的任务时,可以直接根据上述推导柿子来计算当前这一层即可.
IFFT 逆变换
将多项式A和B进行FFT正变换后进行 O(n) 相乘得到多项式C的 2n−1 个点值(y0,y1,⋯,y2n−1)
其中 yi=∑2n−1j=0cj(ωin)j
将这些点值作为系数构造多项式 D(x)=y0+y1x+⋯+y2n−1x2n−1
把所有单位根的倒数 ω0n,ω−1n,⋯ 代入,得到 2n−1 个新点值 z0,z1,⋯
其中 zk=∑2n−1i=0yi(ω−kn)i=∑2n−1i=0∑2n−1j=0cj(ωin)j(ω−kn)i=∑2n−1j=0cj∑2n−1i=0(ωj−kn)i
观察 ∑2n−1i=0(ωj−kn)i, 当 j=k 时,内层和式为 2n
当j≠k 时,内层是个等比数列,运用求和公式可以得到其值为0
所以 zk=(2n)ck, 为方便直接令这里的 2n 为 n (完蛋,好像正变换一直用的是 n 不是 2n,但其实无所谓,知道要取多少个复数根就行),得到 ck=zkn
现在考虑 ω−kn, 其等于 cosθ−isinθ, 其等价于虚部变负
因此 FFT 和 IFFT 完全可以合并成一个函数,只需控制单位根 ωn 的虚部即可.
非递归の实现
观察原序列的二进制形式:
(000,001,010,011,100,101,110,111)
以及递归底层变换后的:
(000,100,010,110,001,101,011,111)
可以发现对应的二进制进行了翻转操作. 我们只需将原有系数的位置调换到其正确的位置,然后通过枚举层数来自底向上归并.
设 F(x) 为其翻转后的数,可以递推得到:
F(x)=F(x2)2+(x个位为1)×n2
总结
干嘛不直接抄板子,这又不是OI
本来想发知乎的,奈何知乎的公式排版一坨答辩