FFT

算法描述,求解对于 A(x)B(x)A(x)B(x) 的卷积,对于某一个多项式 A(x)A(x) 而言
插值多项式的唯一性
对于 nn 个点值对组成的集合 {(x0,y0),(x1,y1),,(xn1,yn1)}\{(x_0, y_0), (x_1, y_1), \cdots, (x_{n-1}, y_{n-1})\}
其中所有的 xkx_k 均不同,那么可以唯一确定次数为 nn 的多项式 A(x)A(x),满足 yk=A(xk)y_k = A(x_k)

带入多项式,等价于方程

(1x0x02x0n11x1x12x1n11xn1xn12xn1n1)(a0a1an1)=(y0y1yn1)\begin{pmatrix} 1 & x_0 & x_0^2 & \cdots & x_0^{n-1} \\ 1 & x_1 & x_1^2 & \cdots & x_1^{n-1} \\ \vdots & \vdots & \ddots & \vdots \\ 1 & x_{n-1} & x_{n-1}^2 & \cdots & x_{n-1}^{n-1} \end{pmatrix} \begin{pmatrix} a_0 \\ a_1 \\ \vdots \\ a_{n-1} \end{pmatrix} = \begin{pmatrix} y_0 \\ y_1 \\ \vdots \\ y_{n-1} \end{pmatrix}

对于 aka_k 有唯一解,其中左边的矩阵表示为范德蒙行列式,该行列式值为

0j<kn1(xkxj)\prod_{0 \leqslant j < k \leqslant n-1} (x_k - x_j)

矩阵可逆,求出唯一的 aaV(x0,x1,,xn1)1yV(x_0, x_1, \cdots, x_{n-1})^{-1} y

给定 nn 次多项式,取 n+1n+1 个点可以将行列式唯一表示出来

根据点表示法,对于 C(x)=A(x)B(x)C(x) = A(x)B(x),可以用 A(x),B(x)A(x), B(x) 的点表示法,假设 A,BA, B 的次数分别为 n,mn, m
n+m+1n+m+1 个点

{(x1,A(x1)),(x2,A(x2)),(xn+m+1,A(xn+m+1))}{(x1,B(x1)),(x2,B(x2)),(xn+m+1,B(xn+m+1))}{(x1,A(x1)B(x1)),(x2,A(x2)B(x2)),(xn+m+1,A(xn+m+1)B(xn+m+1))}\{(x_1, A(x_1)), (x_2, A(x_2)) \cdots, (x_{n+m+1}, A(x_{n+m+1})) \} \\ \{(x_1, B(x_1)), (x_2, B(x_2)) \cdots, (x_{n+m+1}, B(x_{n+m+1})) \} \\ \{(x_1, A(x_1)B(x_1)), (x_2, A(x_2)B(x_2)) \cdots, (x_{n+m+1}, A(x_{n+m+1})B(x_{n+m+1})) \}

这样可以在 O(n+m)O(n+m) 的时间复杂度内求出多项式 C(x)C(x)

普通乘法和点值乘法快速转换

如果能将普通多项式乘法转换成为点值乘法,那么 FFT 是很容易实现的,为此取单位复数根
即满足 ωn=1\omega^{n} = 1 的复数 ω\omegann 次单位根恰好有 nn 个,对于 k=0,1,,n1k = 0, 1, \cdots, n-1
这些根是 e2πik/ne^{2\pi ik / n},利用复数的指数表达,可以写成

eiu=cos(u)+isin(u)e^{iu} = \cos(u) + i\sin(u)

nn 个单位根均匀分布在圆周上,值 ωn=e2πi/n\omega_{n} = e^{2\pi i / n}nn 次单位根
所有其他负数根均为 ωn\omega_{n} 的幂次,这些根构成了一个模 nn 意义下的乘法群,结构如下
ωnjωnk=ωnj+k=ωn(j+k)modn\omega_{n}^{j} \omega_{n}^{k} = \omega_{n}^{j+k} = \omega_{n}^{(j+k) \bmod n},类似地
ωn1=ωnn1\omega_{n}^{-1} = \omega_{n}^{n-1}

消去引理
对于任意 n0,k0,d>0n \geqslant 0, k \geqslant 0, d > 0,我们有

ωdndk=ωnk\omega_{dn}^{dk} = \omega_{n}^{k}

这是显然的,因为 (e2πi/dn)dk=(e2πi/n)k=ωnk(e^{2\pi i / dn})^{dk} = (e^{2\pi i / n})^{k} = \omega_{n}^{k}

那么可以根据消去引理,推出折半引理
对于任意偶数 n>0n > 0,有 ωnn/2=ω2=1\omega_{n}^{n/2} = \omega_{2} = -1
证明也很简单,ωnn/2=ωn/2n/4==ωn/(n/2)n/((n/2)2)=ω2\omega_{n}^{n/2} = \omega_{n/2}^{n/4} = \cdots = \omega_{n/(n/2)}^{n/((n/2) \cdot 2)} = \omega_{2}

根据折半引理

ωnk+n/2=ωnk\omega_{n}^{k + n / 2} = - \omega_{n}^{k}

求和引理
对于任意整数 n1n \geqslant 1 和不能被 nn 整除的非负整数 kk,有

j=0n1(ωnk)j=0\sum_{j = 0}^{n-1} (\omega_{n}^{k})^{j} = 0

可以用等比数列求和

j=0n1(ωnk)j=(ωnk)n1ωnk1=(ωnn)k1ωnk1=(1)k1ωnk1=0\sum_{j = 0}^{n-1} (\omega_{n}^{k})^{j} = \frac{(\omega_{n}^{k})^{n} - 1}{\omega_{n}^{k} - 1} = \frac{(\omega_{n}^{n})^{k} - 1}{\omega_{n}^{k} - 1} = \frac{(1)^{k} - 1}{\omega_{n}^{k} - 1} = 0

DFT

假设 nn22 的整数幂
根据 A(x)A(x) 中偶数下标和奇数下标的系数,定义最高次数为 n/21n/2-1 的多项式 A[0](x)A^{[0]}(x)A[1](x)A^{[1]}(x)

A[0](x)=a0+a2x+a4x2++an2xn/21A[1](x)=a1+a3x+a5x2++an1xn/21A^{[0]}(x) = a_0 + a_2 x + a_4 x^2 + \cdots + a_{n-2}x^{n/2-1} \\ A^{[1]}(x) = a_1 + a_3 x + a_5 x^2 + \cdots + a_{n-1}x^{n/2-1}

那么有 A(x)=A[0](x2)+xA[1](x2)A(x) = A^{[0]}(x^2) + x\cdot A^{[1]}(x^2)

那么可以采用分治策略,对于 k[0,n/21]k \in [0, n/2-1],可以得到

A(ωnk)=A0(ωn2k)+ωnkA1(ωn2k)=A0(ωn/2k)+ωnkA1(ωn/2k)A(\omega_{n}^{k}) = A_0(\omega_{n}^{2k}) + \omega_{n}^{k} A_1(\omega_{n}^{2k}) = A_0(\omega_{n/2}^{k}) + \omega_{n}^{k} A_1(\omega_{n/2}^{k})

而对于 k[n/2,n1]k \in [n/2, n-1],令 kk+n/2,k[0,n/21]k' \leftarrow k+n/2, k \in [0, n/2-1],问题可以转为上述情况,即求 A(ωnk+n/2)A(\omega_{n}^{k+n/2})

A(ωnk+n/2)=A0(ωn2k+n)ωnkA1(ωn2k+n)=A0(ωn/2k)ωnkA1(ωn/2k)A(\omega_{n}^{k + n/2}) = A_0(\omega_{n}^{2k+n}) - \omega_n^k A_1(\omega_n^{2k+n}) = A_0(\omega_{n/2}^{k}) - \omega_{n}^{k} A_1(\omega_{n/2}^{k})

这里用了折半引理

IDFT

接下来需要根据点表示法,逆变换求出卷积系数
已知点表示 (ωnk,A(ωnk))(\omega_{n}^{k}, A(\omega_{n}^{k})),令 ykA(ωnk)y_k \leftarrow A(\omega_{n}^{k})
A(x)=a0+a1x+a2x2++an1xn1A(x) = a_0 + a_1 x + a_2 x^2 + \cdots + a_{n-1}x^{n-1},推导出

ak=1ni=0n1yi(ωnk)ia_k = \frac{1}{n} \cdot \sum_{i = 0}^{n-1} y_i (\omega_{n}^{-k})^{i}

求出 aka_k,实际上也是在求多项式,构造 B(x)=y0+y1x+y2x2+yn1xn1B(x) = y_0 + y_1 x + y_2 x^2 + \cdots y_{n-1} x^{n-1}
ak=1nB(ωnk)a_k = \displaystyle\frac{1}{n}B(\omega_{n}^{-k})
只要求出 B(x)B(x)(ωn0,ωn1,,ωn(n1))(\omega_{n}^{0}, \omega_{n}^{-1}, \cdots, \omega_{n}^{-(n-1)}) 上的值
这也可以通过 DFT\text{DFT} 求出

下面给出证明

ck=i=0n1yi(ωnk)i=i=0n1(j=0n1aj(ωni)j)(ωnk)i=i=0n1(j=0n1aj(ωnj)i(ωnk)i)=i=0n1(j=0n1aj(ωnjk)i)=j=0n1aj(i=0n1(ωnjk)i)\begin{aligned} c_k &= \sum_{i = 0}^{n-1} y_i (\omega_{n}^{-k})^{i} = \sum_{i = 0}^{n-1} \left(\sum_{j = 0}^{n-1}a_j(\omega_{n}^{i})^{j} \right) \cdot \left(\omega_{n}^{-k}\right)^{i} \\ &= \sum_{i = 0}^{n-1}\left(\sum_{j = 0}^{n-1}a_j (\omega_{n}^{j})^{i} (\omega_{n}^{-k})^{i} \right) = \sum_{i = 0}^{n-1}\left(\sum_{j = 0}^{n-1}a_j (\omega_{n}^{j-k})^{i}\right) \\ &= \sum_{j = 0}^{n-1} a_j \left( \sum_{i = 0}^{n-1} (\omega_{n}^{j-k})^{i} \right) \end{aligned}

注意到项 S(ωnk)=(i=0n1(ωnjk)i)S(\omega_{n}^{k'}) = \displaystyle \left( \sum_{i = 0}^{n-1} (\omega_{n}^{j-k})^{i} \right)

其中 ωnkωnjk\omega_{n}^{k'} \leftarrow \displaystyle \omega_{n}^{j-k},根据求和引理,当
k0k' \neq 0S(ωnk)=0S(\omega_{n}^{k'}) = 0
k=0k' = 0 时,ωn0=1\omega_{n}^{0} = 1,那么 S(1)=nS(1) = n

也就是对应 ckc_k 表达式中,j=kj = k 时才有贡献,我们有 ck=nakc_k = na_k,证毕

证明 2,可以考虑用矩阵来证明

根据 yk=A(ωnk)y_k = A(\omega_n^k),系数 aka_k 对应的项就是 ωnk\omega_n^k

(111111ωnωn2ωn3ωnn11ωn2ωn4ωn6ωn2(n1)1ωn3ωn6ωn9ωn3(n1)1ωnn1ωn2(n1)ωn3(n1)ωn(n1)(n1))(a0a1a2a3an1)=(y0y1y2y3yn1)\begin{pmatrix} 1 & 1 & 1 & 1 & \cdots & 1 \\ 1 & \omega_n & \omega_n^2 & \omega_n^3 & \cdots & \omega_n^{n-1} \\ 1 & \omega_n^2 & \omega_n^4 & \omega_n^6 & \cdots & \omega_n^{2(n-1)} \\ 1 & \omega_n^3 & \omega_n^6 & \omega_n^9 & \cdots & \omega_n^{3(n-1)} \\ \vdots & \vdots & \ddots & \ddots & \vdots & \vdots \\ 1 & \omega_n^{n-1} & \omega_n^{2(n-1)} & \omega_n^{3(n-1)} & \cdots & \omega_n^{(n-1)(n-1)} \\ \end{pmatrix} \begin{pmatrix} a_0 \\ a_1 \\ a_2 \\ a_3 \\ \vdots \\ a_{n-1} \end{pmatrix} = \begin{pmatrix} y_0 \\ y_1 \\ y_2 \\ y_3 \\ \vdots \\ y_{n-1} \end{pmatrix}

不妨设 DFT\text{DFT}ωnk\omega_n^k 对应的矩阵是 VnV_n,只需要证明
引理,对于 j,k[0,1,,n1]j, k \in [0, 1, \cdots, n-1]Vn1V_n^{-1}(j,k)(j, k) 处元素为 ωnkj/n\omega_{n}^{-kj} / n

考虑矩阵乘法,Vn1VnV_n^{-1}V_n,对应 (j,k)×(k,j)=(j,j)(j, k) \times (k, j') = (j, j'),考虑 (j,j)(j, j') 的元素

只要证明,我们有 (j,k)(j, k) 元素为 ωnkj/n\omega_{n}^{-kj} / n 的矩阵 VV',能推出该矩阵 VV'Vn1V_n^{-1} 即可

[Vn1Vn]jj=k=0n1(ωnkj/n)ωnkj=k=0n1ωnk(jj)/n\displaystyle [V_n^{-1}V_n]_{jj'} = \sum_{k = 0}^{n-1} \left(\omega_n^{-kj} / n \right) \cdot \omega_{n}^{kj'} = \sum_{k = 0}^{n-1} \omega_n^{k(j - j')} / n

注意此时 (n1)jjn1-(n-1) \leqslant j'-j \leqslant n-1,可以用求和引理
(说明,如果此时 (n1)jj<0-(n-1) \leqslant j'-j < 0,可以用 ωnp=ωnnp\omega_n^{-p} = \omega_n^{n-p} 变换)
如果 j=jj = j',右边等于 11,否则根据求和引理,和为 00
所以 Vn1VnV_n^{-1}V_n 为单位矩阵 InI_n,证毕

FFT 实现

蝴蝶变换
输入向量下标为 (0,1,2,3,4,5,6,7)(0, 1, 2, 3, 4, 5, 6, 7),那么 DFT 递归树叶子结点的下标是 (0,4,2,6,1,5,3,7)(0, 4, 2, 6, 1, 5, 3, 7)
这是根据之前的分析,奇数项写在前面,偶数项写在后面
fft

恰好是二进制表示的位逆序置换,比如 6=1106 = 110,位逆序置换成 011=3011 = 3

这个很好证明,假设最终系数 xx 二进制表示是 ( 1)(\cdots \ 1),那么它是奇数项,一定在 [n/2,n1][n/2, n-1] 这一半的区间
这一半区间中,对应回原来未打乱顺序的数,是较大的一半最高位都是 11
如果二进制表示最低位是 00,即 ( 0)(\cdots \ 0),那么是偶数项
对应回原来的前一半,此时最高位为 00

那么核心是位翻转的实现,这可以递归来做

ri=(ri11)(i & 1)(bit1)r_i = \left(r_{i \gg 1} \gg 1 \right) \mid (i \ \& \ 1) \ll (\text{bit} - 1)

bit\displaystyle \text{bit} 表示最高位的 11 在第几位上

综上所述,FFT\text{FFT} 实现的过程如下

  • 预处理出卷积多项式有 tottot 项,其中 tottot 满足 22bb 次幂,不足可以补 00
    比如 A(x)A(x)n+1n+1 项(最高次幂为 nn),B(x)B(x)m+1m+1 项,那么必须满足 (1b)m+n+2(1 \ll b) \geqslant m+n+2
    tot=(1b)tot = (1 \ll b),则卷积多项式的系数下标范围是 [0,tot)[0, tot)
  • [mid=1,2,22,tot][mid = 1, 2, 2^{2} \cdots, tot] 逐层归并计算,对于每一层,分治区间起始点是 [i=0,i+2mid,i+4mid,,tot)[i = 0, i + 2mid, i + 4mid, \cdots, tot)
    接下来计算 DFT(v1)\text{DFT}(\bm{v_1})DFT(v2)\text{DFT}(\bm{v_2}),根据如上所述的 DFT\text{DFT} 公式
    用折半引理,jj 遍历长度为 midmid前后两半区间,其中前一半下标是 i+ji+j,后一半下标是 i+j+midi+j+mid
    v1=Ai+j+ω2midkAi+j+mid\bm{v1} = A_{i+j} + \omega_{2mid}^{k} \cdot A_{i+j+mid}v2=Ai+jω2midkAi+j+mid\bm{v2} = A_{i+j} - \omega_{2mid}^{k} \cdot A_{i+j+mid}
    具体来说,在算法实现
    每一次迭代循环 mid\text{mid} 的时候,令 ωn=ω2mid=e2πi/2mid=eπi/mid=cos(π/mid)isin(π/mid)\displaystyle \omega n = \omega_{2mid} = \text{e}^{2\pi i / 2 \text{mid}} = \text{e}^{\pi i / \text{mid}} = \cos(\pi / \text{mid}) - i \cdot \sin(\pi / \text{mid})
    x=A(i+j), y=ωnkA(i+j+mid)\bm{x} = A(i+j), \ \bm{y} = \omega n^{k} \cdot A(i+j+mid)
    然后令 A(i+j)x+y, A(i+j+mid)xyA(i+j) \leftarrow \bm{x} + \bm{y}, \ A(i+j+mid) \leftarrow \bm{x} - \bm{y}特别注意,这里 ωnk\omega n^{k} 是可以实时计算的
    只要在归并的开始,即对 jj 循环 for j[0,mid)\textbf{for} \ j \in [0, mid) 前,令 ωnk=1\omega n^k = 1,然后每一次 j++j++ 的时候,令 ωnkωnkωn\omega n^k \leftarrow \omega n^k \cdot \omega n
1