FFT
问题描述
给定 \(n\),有 \(a_{0\sim 2^n-1}\) 和 \(b_{0\sim 2^n-1}\),求出 \(c_{0\sim 2^n-1}\),满足
记其为 \(c=a\ast b\)
符号 和 约定
假定序列的下标从 \(0\) 开始
令 \(\omega_n^x=e^{\frac{2\pi xi}{2^n}}=\cos \frac{2\pi xi}{2^n}+i\sin \frac{2\pi xi}{2^n}\) 表示单位根
令 \(|a|\) 表示序列 \(a\) 的长度
令 \(A_a(x)=\sum_{i=0}^{|a|-1} a_ix^i\),\(L(a)\) 为 \(a\) 的偶数下标形成的子序列,\(R(a)\) 为 \(a\) 的奇数下标形成的子序列
令 \(\text{FFT}_n(a)\) 表示长为 \(2^n\) 的序列 \(a\) 经过 \(\text{FFT}\) 变换的结果,\(\text{FFT}^{-1}_n(a)\) 表示长为 \(2^n\) 的序列 \(a\) 经过 \(\text{IFFT}\) 变换的结果,两者互为逆变换,即 \(\text{FFT}_n(\text{FFT}^{-1}_n(a))=\text{FFT}^{-1}_n(\text{FFT}_n(a))=a\)
令 \(a\cdot b\) 表示数组 \(a\) 和 \(b\) 逐项相乘的结果
基本思想
令 \(\text{FFT}_n(a)_k=A_a(\omega_n^k)\),可证此时对应的 \(\text{IFFT}\) 为 \(\text{FFT}\) 的基础上进行少量额外操作,而 \(\text{FFT}\) 可以用单位根的性质分治优化
由于
可证 \(\text{FFT}^{-1}(\text{FFT}(a)\cdot \text{FFT}(b))\) 的虚部必为 \(0\)
中间的 \(\cdot\) 运算为 \(O(n)\) 的,因此若能在优于 \(O(n^2)\) 的时间复杂度内实现 \(\text{FFT}\) 和 \(\text{FFT}^{-1}\),则能优化 \(c=a\ast b\) 的过程
FFT
对于 \(k<2^{n-1}\),有
对于 \(k\ge 2^{n-1}\),有
对于一个 \(k<2^{n-1}\),考虑 \(\text{FFT}_n(a)_k\) 和 \(\text{FFT}_n(a)_{k+2^{n-1}}\),显然有
据此可分治递归计算,时间复杂度 \(O(n\log n)\)
一般写为非递归形式
IFFT
主要有两种实现
第一种为令单位根为其倒数,进行一次 \(\text{FFT}\),然后全都除以 \(2^n\)
第二种为进行一次 \(\text{FFT}\) 后,全都除以 \(2^n\),然后翻转 \([1,2^n)\)
两者是等价的,时间复杂度都是 \(O(n\log n)\)
性质
\(\text{FFT}\) 为线性变换
优化
假如连续进行多次 \(\ast\) 运算,则可以把所有数组都先进行一次 \(\text{FFT}\),逐项相乘后再进行一次 \(\text{IFFT}\),从而减小常数
对于两项相乘的情况,有一个常用的三次变两次优化:
朴素 \(\text{FFT}\) 为两次正变换和一次负变换,实际上可以优化到一次正变换和一次负变换
复数数组 \(v\),\(\text{Real}(v_i)=a_i,\text{Imag}(v_i)_i\),则 \(c_i=2^{-n-1}\text{Imag}(\text{FFT}^{-1}_n(\text{FFT}_n(v)\cdot \text{FFT}_n(v)))\)
但是这种方法的误差大于朴素 \(\text{FFT}\),需要注意

浙公网安备 33010602011771号