FFT/FNTT 算法笔记
FFT/FNTT 算法笔记
1.前置知识
1.1多项式
多项式
多项式乘法
\(C(x)=A(x)*B(x)\)
多项式的系数表示
多项式的点值表示
多项式求值
从系数表示确定点值表示
多项式的插值
从点值表示确定系数表示
1.2单位根
\(n\) 次单位根
引理 1:
引理 2:
引理 3:
1.3原根
首先取一个特殊的模数 \(p=qn+1,n=2^k,k尽可能大\)
\(n\) 次单位根
若 \(g_n^{n/2}=1\)则\(g^{(p-1)/2}=1\)违反原根性质,舍去
引理 1:
引理 2:
引理 3:
2 递归 FFT
FFT 是多项式求值和插值的一种 \(\Theta(n \log n)\) 算法。
首先假设 \(n=2^k\)
然后根据下标二进制表示的末位是 1 还是 0 分成两个多项式
那么在FFT中递归做这两个子问题 \(A_0,A_1\),边界是 \(n=1\)
根据引理2,可以把单位根的规模从 \(n\) 缩小到 \(n/2\)
然后在主函数中处理:
对于 \(k<n/2\) 的
直接按照式子转移
对于 \(k>n/2\)
\(w_n^k=-w_n^{k-n/2}\) 然后转移
对于插值过程只需要找到范德蒙德矩阵的逆矩阵即可
具体详见《算法导论》,这里给出结论:将 \(-w_n^k/n\) 代替 \(w_n^k\) 带入即可
关于时间复杂度 \(T(n)=2T(n/2)+\Theta(n)=\Theta(n \log n)\)
3 非递归 FFT
一种原地优化的FFT,时空码三方面好于递归版。
注意到代码中这一段
\( for\ k=0 \ to \ n/2-1\\ \qquad y_k = y0_k+w_n^k\,y1_k\\ \qquad y_{k+n/2} = y0_k-w_n^k\,y1_k\\ \)
这里只使用到了 \(y0_k,y1_k,y_k,y_{k+n/2}\) 这些值,于是考虑对他们进行原地变换(蝴蝶操作)。
那么这需要确定递归到最底层的顺序,然后循环操作,从下往上,就可以实现非递归FFT了。注意这里的蝴蝶操作需要设置一个临时变量。
接下来确定递归到最底层的顺序。
[000 001 010 011 100 101 110 111]
[000 010 100 110] [001 011 101 111]
[000 100] [010 110] [001 101] [011 111]
[000] [100] [010] [110] [001] [101] [011] [111]
规律是一个位置递归到最底层,就是它的二进制位翻转所对应的位置。设\(n=2^s\),因为对于某一个递归深度 \(t\)。这时候这些位置的前 \(t-1\) 位都相同。\(t\) 位为0的书到达左侧,而这些位置,正好他们的 \(s-1-t\) 位都是0。反之,1的情况同理。所以这个规律成立。
这个不过是常数优化。
4 FNTT(整数FFT)
如果FFT里全是整数,如何防止掉精度呢?
尝试对某个数取模(模数最好大于它乘完得到的数),使用原根替换单位根。
观察引理是否仍然成立,在第一章已经做过说明
所以可以使用原根替换单位根,然后一切照旧。
5 分治 FFT
推荐阅读:
ABC213H Editorial,
P4721
对于后面依赖前面的dp转移,使用cdq分治的思想递归掉前面,然后卷积前面转移到后面,再递归到后面。
代码实现 ABC2113H

浙公网安备 33010602011771号