快速数论变换(NTT)

开头

NTT就是对FFT进行了改进,上一篇中讲了FFT,可以看到FFT所用的单位根 w n k w_n^k wnk 的实部和虚部都是通过正弦余弦函数计算而来的,所以不可避免地会有很多浮点数运算

所以NTT就是在整数范围内寻找和单位根有相同性质的那些数,可以提升计算的精度

这种整数被找到了,就是原根
        

欧拉函数

对于一个正整数 n,小于等于 n 且与 n 互质的正整数的个数,记作 φ ( n ) \varphi(n) φ(n),有
φ ( x ) = x ( 1 − 1 P ( 1 ) ) ( 1 − 1 P ( 2 ) ) . . . . . . ( 1 − 1 P ( n ) ) \varphi(x) = x(1 - \frac{1}{P(1)})(1 - \frac{1}{P(2)})......(1 - \frac{1}{P(n)}) φ(x)=x(1P(1)1)(1P(2)1)......(1P(n)1)其中 P ( k ) P(k) P(k) x x x 的质因数,且相同的 P ( k ) P(k) P(k) 只会出现一次

如:
φ ( 99 ) = 99 × ( 1 − 1 3 ) × ( 1 − 1 11 ) = 60 φ ( 15 ) = 99 × ( 1 − 1 3 ) × ( 1 − 1 5 ) = 8 \begin{aligned} \varphi(99) &= 99 ×(1 - \frac{1}{3})×(1 - \frac{1}{11}) \\ &= 60 \\ \varphi(15) &= 99 ×(1 - \frac{1}{3})×(1 - \frac{1}{5}) \\ &= 8 \end{aligned} φ(99)φ(15)=99×(131)×(1111)=60=99×(131)×(151)=8

定义:假设 m > 1 m > 1 m>1,且 g c d ( a , m ) = 1 gcd(a, m) = 1 gcd(a,m)=1 a a a m m m 互质),那么使得 a r ≡ 1 m o d    m a^r ≡ 1 \mod m ar1modm 成立的最小的整数 r r r,称为 a a a 对模 m m m 的阶,记作
δ m ( a ) \delta_m(a) δm(a)

原根

如果有
δ m ( a ) = φ ( m ) \delta_m(a) = \varphi(m) δm(a)=φ(m)则称 a a a 为模 m m m 的一个原根


举个例子:

m = 7 m = 7 m=7,则 φ ( m ) = 7 × ( 1 − 1 7 ) = 6 \varphi(m) = 7×(1-\frac{1}{7})=6 φ(m)=7×(171)=6

一个一个取 a a a

a = 2 , 2 3 = 8 ≡ 1 m o d    7 得 到 δ 7 ( 2 ) = 3 ∵ 3 < 6 , ∴ δ 7 ( 2 ) ≠ φ ( 7 ) 2 不 是 模 7 的 原 根 a = 3 , 3 k ≠ 1 m o d    7 , k ∈ [ 1 , 5 ] 3 6 = 729 ≡ 1 m o d    7 得 到 δ 7 ( 3 ) = 6 ∵ 6 = 6 , ∴ δ 7 ( 3 ) = φ ( 7 ) 3 是 模 7 的 原 根 \begin{aligned} a = 2, & 2^3 = 8 ≡ 1 \mod 7\\ &得到\delta_7(2) = 3\\ & ∵ 3 < 6,∴\delta_7(2) ≠ \varphi(7)\\ & 2不是模7的原根\\ a = 3, & 3^k ≠ 1 \mod 7,k∈[1, 5]\\ & 3^6 = 729 ≡ 1 \mod 7\\ &得到\delta_7(3) = 6\\ & ∵ 6 = 6,∴\delta_7(3) = \varphi(7)\\ & 3是模7的原根 \end{aligned} a=2a=323=81mod7δ7(2)=33<6δ7(2)̸=φ(7)273k̸=1mod7,k[1,5]36=7291mod7δ7(3)=66=6δ7(3)=φ(7)37
原根就具有单位根的性质,使得它可以和单位根一样进行运算

原根存在的条件是:
m = 2 , 4 , p n , 2 p n m = 2, 4, p^n, 2p^n m=2,4,pn,2pn,这里 p p p 为奇素数, n n n 为正整数
        

NNT

这里我们取
g P − 1 n m o d    P = w n g^{\frac{P-1}{n}} \mod P= w_n gnP1modP=wn其中 g g g P P P 的原根,这样就可以用左式代替右式进行类FFT计算,即用整数代替了浮点数

这里 P P P 通常取998244353、1004535809,它们的原根 g g g 均为 3

那NNT就是将FFT中的单位根换成了原根

如果说FFT的核心代码如下的话:

x = a[j + k];
y = w * a[j + k + mid];
a[j + k] = x + y;
a[j + k + mid] = x - y;

那NNT的核心代码就是这样:

x = a[j + k];
y = w * a[j + k + mid];
a[j + k] = (x + y) % P;
a[j + k + mid] = (x - y + P) % P;

你可能感兴趣的:(算法整理)