开头
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(1−P(1)1)(1−P(2)1)......(1−P(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×(1−31)×(1−111)=60=99×(1−31)×(1−51)=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
ar≡1modm 成立的最小的整数
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×(1−71)=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=2,a=3,23=8≡1mod7得到δ7(2)=3∵3<6,∴δ7(2)̸=φ(7)2不是模7的原根3k̸=1mod7,k∈[1,5]36=729≡1mod7得到δ7(3)=6∵6=6,∴δ7(3)=φ(7)3是模7的原根
原根就具有单位根的性质,使得它可以和单位根一样进行运算
原根存在的条件是:
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
gnP−1modP=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;