2020年了我怎么还是没有学会任意模数NTT……
发现自己多项式的技能没有点的还有很多。
处理任意模数NTT有一系列的方法,其中有个看起来比较优的算法需要FFT三次变二次优化。
众所周知,普通的FFT长这样:
假设是多项式(A(x))和(B(x))求卷积,首先求(DFT(A))和(DFT(B)),两者相乘后求(IDFT)
这样算了三次(DFT)。
接下来的算法可以将三次(DFT)优化成两次。
设(P(x)=A(x)+iB(x)),(Q(x)=A(x)-iB(x))
推一波式子(设(L)表示长度,( heta=frac{2pi jk}{L}))
[DFT(P)_k=P(omega^k)\
=sum_{j=0}^{L-1}(A_j+iB_j)omega^{jk} \
=sum_{j=0}^{L-1}(A_j+iB_j)(cos heta + isin heta) \
=sum_{j=0}^{L-1}(A_jcos heta-B_jsin heta)+i(A_jsin heta+B_jcos heta)]
[DFT(Q)_k=Q(omega^k)\
=sum_{j=0}^{L-1}(A_j-iB_j)omega^{jk} \
=sum_{j=0}^{L-1}(A_j-iB_j)(cos heta + isin heta) \
=sum_{j=0}^{L-1}(A_jcos heta+B_jsin heta)+i(A_jsin heta-B_jcos heta) \
=sum_{j=0}^{L-1}(A_jcos(- heta)-B_jsin(- heta))-i(A_jsin(- heta)+B_jcos(- heta))]
对比一下,可以发现(DFT(Q)_k)和(DFT(P)_{L-k})(即(DFT(P)_{-k}))共轭。
于是算出(DFT(P)),就可以在(O(n))时间内求出(DFT(Q))。
显然(A(x)=frac{P(x)+Q(x)}{2}),(B(x)=-ifrac{P(x)-Q(x)}{2})
于是就可以求出(DFT(A))和(DFT(B)),进而求出(DFT(A*B)),然后(IDFT)回去。
这样就将(DFT)从调用三次优化到调用两次了。