【学习杂谈】快速变换 - 傅里叶与沃尔什
序列变换好像有一些相似的部分?让我们把它抽象出来加深理解。
快速傅里叶变换 FFT
前置知识
我们有欧拉公式 \(e^{i\theta }= \cos \theta + i\sin\theta\)
当把 \(theta\) 替换为 \(\frac{2\pi}{n}\times k\) 时,复数可视作向量在单位圆上均分为 \(n\) 个部分的第 \(k\) 个点,以单位根 \(w_n^{k}\) 表示。
可得两个性质:
- \(w_{2n}^{2k} = w_{n}^{k}\)
- \(w_n^a + w_n^b = w_n^{a+b}\)
快速傅里叶变换
我们有两个 \(n\) 次多项式 \(F1(x)\) 和 \(F2(x)\),希望快速得到 \(F1(x)\times F2(x)\) 的每一项的系数。
直接两两相乘是 \(O(n^2)\) 的。
但已知 \(n+1\) 个点可以唯一确定一个 \(n\) 次多项式,如果将两个多项式都变成 \(2n+ 1\) 个点 \((x_i,f(x_i))\) 表示的形式,两个多项式相乘变成了对应x位置点值相乘,乘法复杂度 \(O(n)\)。然而系数表示和点值表示的相互转换复杂度 \(O(n^2)\)。
怎么把转换复杂度变成 \(log\) 呢?
假设现在多项式恰好有 \(2^q\) 次项,设多项式的点值表示的序列为 \(F(x)\),那么令奇偶下标分别为一组,奇数为 \(Fl(x)\),偶数为 \(Fr(x)\),可得到:
\(F(x) = Fl(x^2) + x\times Fr(x^2)\)
如果将 x 以单位根替换,则:
\(F(w_n^k) = Fl(w_{n/2}^k) + w_n^k \times Fr(w_{n/2}^k)\)
\(F(w_n^{k+n/2}) = Fl(w_{n/2}^k) - w_n^k \times Fr(w_{n/2}^k)\) (此处省略推导)
可发现每次的数据范围是缩小了一半的,于是我们可以在 \(n \log n\) 的时间内分治求出多项式点值表示。
上述过程被称为 \(DFT\) ,\(DFT\) 求得的序列第 \(i\) 项是原序列 \(F(x)\) 在 \(x=w_n^{i-1}\) 处的值。
\(DFT\) 的过程也可被视作把原序列看作一个向量F,左乘了一个变换矩阵 \(W\)。
左乘后多项式由系数表示转换为点值表示,点值表示左乘 \(W\) 的逆矩阵得到系数表示。恰巧 \(W^{-1}\) 中每一项的系数是 \(W\) 的相反数。
由此可在 \(nlogn\) 时间内完成多项式快速乘法
快速沃尔什变换 FWT/FMT
快速傅里叶变换要做的是 \(c_k=\sum_{i+j=k}a_i \times b_j\)
快速沃尔什变换要做的是 \(c_k=\sum_{i op j = k} a_i\times b_j\)
\(op\) 操作是and、or、xor其中一种。
仿照FFT的操作,我们要将序列乘一个矩阵变换且这个矩阵有逆变换使得序列变换后能转为单点乘积。
在此直接给出构造。
令\(A\) 表示原序列,\(A0\) 表示前一半,\(A1\) 表示后一半。
或:\(FWT(A)=merge(A0,A0+A1)\),逆变换为 \(IFWT(A')=merge(A0',A1'-A0')\)。
与:\(FWT(A)=merge(A0+A1,A0)\),逆变换为 \(IFWT(A')=merge(A0'-A1',A1')\)。
异或:\(FWT(A)=merge(A0+A1,A0-A1)\),逆变换为 \(IFWT(A')=merge(\frac{A0'+A1'}{2},\frac{A0'-A1'}{2})\)。
序列的变换矩阵可视作 \(2\times 2\) 的小矩阵的张量积,因此复杂度是 \(logn\) 的。
与FFT做比较,FFT的DFT矩阵并不能完全分解成小矩阵的张量积,因为不同位置的 \(w_n^k\) 不同,因此每层都有不同的对角旋转矩阵,但DFT同样可以将序列的长度减半,并在\(O(n)\)时间内完成不同的对角旋转,因此是 \(nlogn\) 的。同时因为每层的蝴蝶变换矩阵完全相同,可以一次性同时做完 \(logn\) 层的蝴蝶变换。

浙公网安备 33010602011771号