FFT

FFT 流程

  • P1919 【模板】A*B Problem 升级版(FFT 快速傅里叶变换) 为例

  • 一个数字可以看成 \(a_i\times 10^i\) ,那么把两个数字转成多项式的形式,求最后每一项的系数

  • 我们知道一个多项式可以通过 \(n\) 个系数,或者 \(n+1\) 个点值来确定,那么我们考虑快速的让两个多项式转换成点值表示,然后点值的值是可以直接乘起来的,然后再通过得到的 \((f*g)\)\(n+1\) 个点值转回系数

  • FFT 要求长度为 \(2^n\) ,所以不够的补 0

系数转点值

  • 对于函数 \(f(x)=a_0+a_1x+a_2x^2+...\)

  • \(f(x)=(a_0+a_2x^2+a_4x^4+...)+x(a_1+a_3x^2+a_5x^4+...)\)

  • \(G(x)=a_0+a_2x+a_4x^2...,H(x)=a_1+a_3x+a_5x^2...\)

  • 那么 \(f(x)=G(x^2 )+xH(x^2)\)

  • 注意到这个 \(x\) 我们取单位根 \(w_n^k,0\leq k\leq n\) ,之所以这个取是因为单位根是 \(x^n=1\) 在复数域下的解,幂次最后得出是 1 会方便我们计算

  • 单位根有一些性质:

    • \(w_n^n=1\)
    • \(w_{2n}^{2k}=w_n^k\)
    • \(w_{2n}^{n+k}=-w_{2n}^k\)
  • 那么最后就会得到

    • \(0<x<\frac{n}{2},f(w_n^x)=G(w_{n/2}^k)+w_n^kH(w_{n/2}^k)\)
    • \(\frac{n}{2}\leq x<n,f(w_n^x)=G(w_{n/2}^k)-w_n^kH(w_{n/2}^k)\)
  • 可以发现中间的符号不同,其他都是一样的,那么我们只要递归求 \(G(x)\)\(H(x)\) 就可以了

  • 最后得到的函数的每一位是相应的点值

  • 复杂度为 \(O(n\log n)\) ,递归写法

蝴蝶变换

  • 观察发现编号为 \(x(2)\) 的下标,最后会变到 \(rev(x(2))\) 的下标

  • 这个可以预处理出来,将每个数变换到对应的地方,那么就可以直接递推处理

  • 具体的变换可以参照 rev[i]=(rev[i>>1]>>1)|((i&1)<<(L-1));

点值转系数

  • 实际上这个时候一般的高斯消元可以列出一个矩阵,具体可见 OI-Wiki

  • 我们惊喜的发现这个系数矩阵是可逆的,并且逆矩阵的每个位置就是原来的数倒一下再除以 n

  • 这个除以 n 可以放在最后再一起除

  • 然后此时已经求出的点值乘上逆矩阵就等于原系数

  • 我们将点值看成系数,系数看成新的点值,那么就转换成了之前的 快速系数转点值

  • 因为只是倒一下,所以符号上有一点不同,其他的都是一样的

参考代码

8 次MTT

  • FFT 的精度损失是一方面,另一方面无法像 NTT 那样做大值域,因为没办法取模

  • 于是就有了拆系数 FFT ,也叫 MTT

  • P4245 【模板】任意模数多项式乘法 为例

  • 一种方法是直接将一个函数 \(f(x)\) 拆成 \(f(x)/M\)\(f(x)\%M\)

  • \(f(x)=M\times (f(x)/M)+(f(x)\%M)=Mf_1(x)+f_2(x)\)

  • 那么 \(f(x)g(x)=M^2f_1g_1+f_2g_2+Mf_1g_2+Mf_2g_1\) ,那么就要做 8 次 FFT

  • \(M\)\(2^{15}\) 最好,开 long double 信仰的跑,值域是解决了,但是常数巨大

4 次 MTT

  • 首先还是像上面一样拆式子,那么现在有 \(A_0,A_1,B_0,B_1\) 四个系数式,我们希望通过 2 次 DFT 得到它们各自的点值

  • 构造系数式 \(P=A_0+iB_0,Q=A_0-iB_0\)

  • 注意到 \(P,Q\) 的每一项都共轭,那么它们的点值也共轭,那么我们求出 \(P\) 的点值,然后推出 \(Q\) 的点值,然后类似于解一元二次方程来解出 \(A_0,B_0\)

  • 那么分成两组,一共就是 2 次 DFT

  • 现在得到了 \(A_0,A_1,B_1,B_0\) 的点值

  • 更抽象的,现在有 4 个点值式 \(A,B,C,D\) ,我们希望通过 2 次 IDFT 得到它们两两乘积的系数式

  • 构造 \(P=A+iB,Q=C+iD,Q'=C-iD\)

  • 那么 \(PQ=AC+iBC+iDA-BD,PQ'=AC+iBC-iDA+BD\)

  • 通过 2 次 IDFT 可以得到上述式子

  • 因为最终的答案不存在虚部,那么就可以通过虚部和实部分别解出 \(AC,BC,BD,DA\) ,正好符合我们的要求

  • 那么总的就是要进行 4 次 FFT

posted @ 2022-06-04 11:10  Kzos_017  阅读(43)  评论(0编辑  收藏  举报