FFT & NTT 复习笔记
默认文中的形如 [l,r) 的区间为其与整数集的交集。
快速变换
设原多项式为 F(x)=∑i∈[0,n)aixi,其中 n=2k,k∈Z+。
我们要求 ∀i∈[0,n),a^i=F(ti),其中 t 是一个长度为 n 且两两互不相同的序列。
显然 F 可以被一组 a^,t 唯一确定,即点值表示法。
另设两个多项式
G0(x)=a0+a2x+⋯+an−2x2n−1G1(x)=a1+a3x+⋯+an−1x2n−1
则有
F(x)=i∈[0,n)∑aixi=a0+a1x+a2x2+⋯+an−1xn−1=(a0+a2x2+⋯+an−2xn−2)+(a1x+a3x3+⋯+an−1xn−1)=G0(x2)+xG1(x2)
考虑构造单位根 ωnk 满足 ωn2n=−1,ω2n2k=ωnk。
显然也有 ωnn=ωn0=1。
设 ∀i∈[0,n),ti=ωni。
当 x=ωnk,k∈[0,2n) 时显然有
F(ωnk)=G0(ωn2k)+ωnkG1(ωn2k)=G0(ω2nk)+ωnkG1(ω2nk)
当 x=ωnk+2n,k∈[0,2n) 时有
F(ωnk+2n)=G0(ωn2k+n)+ωnk+2nG1(ωn2k+n)=G0(ωn2k⋅ωnn)−ωnkG1(ωn2k⋅ωnn)=G0(ωn2k)−ωnkG1(ωn2k)=G0(ω2nk)−ωnkG1(ω2nk)
由于两者只有一个符号的差异,于是 F 的点值可以直接 O(n) 从 G0,G1 的点值得到。
递归解决,时间复杂度 O(nlogn)。
逆变换
设变换后的点值序列为 a^,即
∀i∈[0,n),a^i=F(ωni)=j∈[0,n)∑aj(ωni)j=j∈[0,n)∑ajωnij
设多项式 F^(x)=∑i∈[0,n)a^ixi。
对 F^ 进行点值变换(∀i∈[0,n),ti=ωn−i),设点值序列为 s。
则有
∀i∈[0,n),si=F^(ωn−i)=j∈[0,n)∑a^j(ωn−i)j=j∈[0,n)∑ωn−ija^j=j∈[0,n)∑ωn−ijk∈[0,n)∑akωnjk=j∈[0,n),k∈[0,n)∑ωn−ijakωnjk=j∈[0,n),k∈[0,n)∑ωnj(k−i)ak=k∈[0,n)∑akj∈[0,n)∑ωnj(k−i)=k∈[0,n)∑akj∈[0,n)∑(ωnk−i)j
显然第二个求和是一个等比数列,由等比数列求和公式 ∑i∈[m,n)pi=1−ppm−pn 得:
- 当 ωnk−i=1⟺i=k
j∈[0,n)∑(ωnk−i)j=1−ωnk−i1−ωn(k−i)n=1−ωnk−i1−(ωnk−i)n=1−ωnk−i1−1=0
- 当 ωnk−i=1⟺i=k
j∈[0,n)∑(ωnk−i)j=j∈[0,n)∑1=n
因此
∀i∈[0,n),si=k∈[0,n)∑akj∈[0,n)∑(ωnk−i)j=nai
于是我们有
∀i∈[0,n),ai=nsi
构造单位根
在复数域下,有 ωn=cosn2π+isinn2π。
其中 i=−1 是 虚数单位,可以用 C++
中的 complex
库中的 std::complex<double/long double>
存储复数。
对于模数 P∈P,∃n,k∈Z+,P=2nk+1,在模 P 意义下有 ωn≡gnP−1,其中 g 是原根。
g 是模 P 意义下的原根当且仅当 gi≡1(modP),∀i∈[1,ϕ(P)) 且 gϕ(P)≡1(modP)。
specially,∀P∈P,其原根 g 满足 ∀i∈[1,P−1),gi≡1(modP) 且 gP−1≡1(modP)。
于是对 n=2m,m∈Z+,我们有 ωnn≡gnP−1⋅n≡gP−1≡1,(modP),且 ωn2n≡g2P−1≡±gP−1≡±1(modP),又 g2P−1≡1(modP),所以 ωn2n≡−1(modP)。
还有 ω2n2k≡g2n2k(P−1)≡gnk(P−1)≡ωnk(modP)
由于原根的特殊性,模数 P∈P 有特殊的限制,一般有 P=k2m+1,k,m∈Z+。
常见的模数有
167772161=5×225+1,g=3469762049=7×226+1,g=3754974721=45×224+1,g=11998244353=119×223+1,g=31004535809=479×221+1,g=3