在 FFT 中,需要用到复数和 double,这有两个问题:精度较低和无法实现取模。
所幸,这两个问题都可以用一个东西解决:NTT。
NTT 所解决的问题和 FFT 相似:
有两个多项式 f(x)=a0+a1x1+a2x2+⋯+akxk, g(x)=b0+b1x1+b2x2+⋯+blxl。
求 h(x)=f(x)⋅g(x) ,但 h(x) 每项系数对 P 取模。
我们考虑用一个叫做原根的东西代替单位根,设 n 次单位根为 ωn 。
四条性质
在 FFT 中所用到了四条单位根的性质,它们是:
-
对于 0≤i<n , ωni 各不相同。
-
折半定理 ωni = ω2n2i ,用于分治。
-
ωni = -ωni+2n ,用于分治。
-
对于 t=∑i=0n−1ωnki , 当 k=0 时, t=n ,否则 t=0 ,用于 IDFT 。
对于质数 P=2tq+1 ,其的原根 g 为满足 gi,0≤i<P 互不相同的数。
考虑这四个性质,令 n=2t , ωn=gq :
-
显然 0≤0,q,2q,⋯,(n−1)q<P ,故 ω0,ω1,ω2,⋯,ωn−1<P 互不相同,满足。
-
ω2n2i=(g2n)2i=gni=ωni
-
根据费马小定理 ωn=gP−1=1 (mod P),又因为 (ω2n)2=ωn=1 ,所以 ω2n=1 or −1 ,又因为 gi 互不相同,所以 ω2n=−1 ,所以 ωni=−ωni+2n
-
当 k=0 时
S(k)ωkS(k)ωkS(k)−S(k)S(k)=(ωk)0+(ωk)1+⋯+(ωk)(n−1)=(ωk)1+(ωk)2+⋯+(ωk)n=(ωk)n−1=ωk−1ωnk−1
由于 ωnmodP=1 ,所以 ωnk−1modP=0 ,所以 S(k)=0 。
求原根
先略过,记住几个常用的模数的原根。
P |
分解 |
g |
998244353 |
7×17×223+1 |
3 |
1004535809 |
479×221+1 |
3 |
参考资料
oi-wiki.org
「Menci」大大的博客