个人博客同步食用~
本博客学习于洛谷P3803各路大佬题解,所以你肯定会找到很多相似的地方QWQ
什么是FFT
傅里叶变换
傅里叶说明了:一切函数/波形都可以用有限或无限个弦函数/波形叠加形成。
例如,现在有一个由三个不同正弦波组成的近似矩形波,将这些波形关于 x x x 轴平行地放在一起,就可以得到下图:
其中红色的是合成出来的近似矩形波。
(当然,图肯定是不太标准的,意思一下就行)
从 x O z xOz xOz 平面看,我们可以获得各个波的时域信号,也就是 t − f ( t ) t-f(t) t−f(t) 图像。而从 z O y zOy zOy 平面看,则可以获得各个波的频域信号。
先不看频域信号中的红色部分,注意其他三个波其实是有排序规则的:按照频率大小排序。也就是说,频率越快, y y y 越大。且每个频率下的 z z z 将反映该波的振幅。两种不同的信号包含了不同的信息。
而傅里叶变换,就是对一个时域信号作变换,生成频域信号。
离散傅里叶变换(DFT)
顾名思义,离散傅里叶变换就是在确定时域信号和频域信号都是离散的时候作的傅里叶变换。
例如,现在有一个多项式函数 f ( x ) = ∑ i = 0 n a i x i f(x)=\sum_{i=0}^{n}a_ix^i f(x)=∑i=0naixi,那么这个函数其实就是“时域信号”,我们也可以将其表示成点集 { P 0 , P 1 , . . . , P n } \{P_0,P_1,...,P_n\} { P0,P1,...,Pn},其中 P i P_i Pi 是函数图像上的某一个点。容易知道 n n n 个点是可以确定一个 n − 1 n-1 n−1 次多项式的。那么这个点集其实就是“频域信号”。从函数式到点集的变化,就是一种离散傅里叶变换。
另外,我们称IDFT为DFT的逆运算,即从点集得到函数式的运算。
为什么需要FFT
离散型傅里叶变换解决的问题一般是多项式乘法问题。
最经典的FFT问题即多项式卷积问题:
P3803 【模板】多项式乘法(FFT) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
给一个 n n n 次多项式 F ( x ) F(x) F(x) 和一个 m m m 次多项式 G ( x ) G(x) G(x),求 F ( x ) F(x) F(x) 和 G ( x ) G(x) G(x) 的卷积。
如果直接暴力计算,第一种就是直接展开函数式算,第二种就是执行一次DFT,将函数式转换为点集,通过对 x x x 相同的点的 y y y 值相乘,得到目标函数的点集,再通过 DFT 的逆运算 IDFT 转化为答案。
显然,不管采取哪种方法,一共都有 m ⋅ n m · n m⋅n 项,复杂度为 O ( ( m a x { n , m } ) 2 ) O((max\{n, m\})^2) O((max{ n,m})2). 在 n m ≥ 1 e 9 nm\geq 1e9 nm≥1e9 的时候是无法接受的。虽然朴素方法下第二种方法的常数肯定比第一种还要大,但其实我们可以在DFT变换的基础上使用FFT来加速多项式乘法。实际上,FFT的加速原因在于其采用了分治的思想。
多项式乘法问题
前置知识-复数根
考虑欧拉公式
e θ i = cos θ + i sin θ e^{\theta i}= \cos\theta + i\sin\theta eθi=cosθ+isinθ
,容易知道 e 2 π i = 1 e^{2\pi i}=1 e2πi=1.
不妨令 w n = e 2 π i n = sin 2 π i n + i cos 2 π i n w_n=e^{2\pi i\over n}=\sin{2\pi i\over n}+i\cos{2\pi i\over n} wn=en2πi=sinn2πi+icosn2πi, 则 w n n = 1 w_n^n=1 wnn=1.
则称 w n w_n wn 为 n n n 的一个复数单位根. 容易知道 n n n 的复数根最多有 n n n 个,为 { w i ∣ i ∈ [ 0 , n − 1 ] } \{w_i|i\in [0,n-1]\} { wi∣i∈[0,n−1]}. 这是因为复数根具有性质 w n n + k = w n k w_n^{n+k}=w_n^k wnn+k=wnk.
另外,还有一个通过消去定理得到的引理: w n k = w n 2 k 2 w_n^k=w_{n\over2}^{k\over2} wnk=w2n