参考 jklover 的笔记
参考 rvalue 的笔记
参考 yx 的笔记
参考 Great_Influence 的笔记
参考 zerol 的笔记
CRT
解模数互质的线性同余方程组 { x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) x ≡ a 3 ( m o d m 3 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} \begin{array}{rcl} x&\equiv& a_1\pmod{m_1}\\ x&\equiv& a_2\pmod{m_2}\\ x&\equiv& a_3\pmod{m_3}\\ &\vdots&\\ x&\equiv& a_n\pmod{m_n}\\ \end{array} \end{cases} ⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧xxxx≡≡≡⋮≡a1(modm1)a2(modm2)a3(modm3)an(modmn)
其中,模数
m
1
⋯
m
n
m_1\cdots m_n
m1⋯mn 两两互质(并不要求全部都是素数)。
怎么解呢……我先不讲思路,你对着下面的过程康一遍?
设 N = ∏ i = 1 n m i N=\prod\limits_{i=1}^nm_i N=i=1∏nmi 。
-
考虑到 m i m_i mi 和 N m i \frac{N}{m_i} miN 互质,
对每个 i i i 用寻找 y i y_i yi 满足 N m i ⋅ y i ≡ 1 ( m o d m i ) \frac{N}{m_i}\cdot y_i\equiv1\pmod{m_i} miN⋅yi≡1(modmi) -
为了方便记 x i = N m i ⋅ y i x_i=\frac{N}{m_i}\cdot y_i xi=miN⋅yi
那么有:
x i a i ≡ a i ( m o d m i ) x_ia_i\equiv a_i\pmod{m_i} xiai≡ai(modmi)
- 并且
x
i
a
i
=
N
y
i
a
i
m
i
x_ia_i=\frac{Ny_ia_i}{m_i}
xiai=miNyiai
显然 ∀ j ≠ i \forall j\ne i ∀j̸=i 有 m j ∣ N m i m_j|\frac{N}{m_i} mj∣miN
那么有:
x i a i ≡ 0 ( m o d m j ) x_ia_i\equiv0\pmod{m_j} xiai≡0(modmj)
上面的东西简单讲就是
x
i
≡
N
m
i
⋅
[
(
N
m
i
)
−
1
m
o
d
  
m
i
]
(
m
o
d
N
)
x_i\equiv\frac{N}{m_i}\cdot\left[(\frac{N}{m_i})^{\bm-1}\mod{m_i}\right]\pmod{N}
xi≡miN⋅[(miN)−1modmi](modN)
不难发现这个东西的大体思路跟拉格朗日插值是很像的
显而易见地:
x
≡
∑
i
=
1
n
x
i
a
i
(
m
o
d
N
)
x\equiv\sum\limits_{i=1}^nx_ia_i\pmod{N}
x≡i=1∑nxiai(modN) 总复杂度
O
(
n
log
N
)
O(n\log N)
O(nlogN)
ExCRT
解任意模数的线性同余方程组 { x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) x ≡ a 3 ( m o d m 3 ) ⋮ x ≡ a n ( m o d m n ) \begin{cases} \begin{array}{rcl} x&\equiv& a_1\pmod{m_1}\\ x&\equiv& a_2\pmod{m_2}\\ x&\equiv& a_3\pmod{m_3}\\ &\vdots&\\ x&\equiv& a_n\pmod{m_n}\\ \end{array} \end{cases} ⎩⎪⎪⎪⎪⎪⎨⎪⎪⎪⎪⎪⎧xxxx≡≡≡⋮≡a1(modm1)a2(modm2)a3(modm3)an(modmn)
复杂度跟 CRT 一毛一样。
它的想法很简单暴力,就是把方程两两逐个合并
考虑 { x ≡ a 1 ( m o d m 1 ) x ≡ a 2 ( m o d m 2 ) \begin{cases}\begin{array}{rcl} x&\equiv& a_1\pmod{m_1}\\ x&\equiv& a_2\pmod{m_2}\\ \end{array}\end{cases} {xx≡≡a1(modm1)a2(modm2)
x
0
=
k
1
m
1
+
a
1
=
k
2
m
2
+
a
2
x_0=k_1m_1+a_1=k_2m_2+a_2
x0=k1m1+a1=k2m2+a2
k
1
m
1
−
k
2
m
2
=
(
a
2
−
a
1
)
k_1m_1-k_2m_2=(a_2-a_1)
k1m1−k2m2=(a2−a1) 直接裸上 ExGCD
把
k
1
k_1
k1 或者
k
2
k_2
k2 对
m
2
m_2
m2 或者
m
1
m_1
m1 取模(避免过大)然后代回自家式子
为什么交叉取模?你可以考虑挪一下就变成两条式子:
{ k 1 m 1 ≡ a 2 − a 1 ( m o d m 2 ) k 2 m 2 ≡ a 1 − a 2 ( m o d m 1 ) \begin{cases}\begin{array}{rcl} k_1m_1&\equiv& a_2-a_1\pmod{m_2}\\ k_2m_2&\equiv& a_1-a_2\pmod{m_1}\\ \end{array}\end{cases} {k1m1k2m2≡≡a2−a1(modm2)a1−a2(modm1)
解出
x
0
x_0
x0 得到合并后的方程
x
≡
x
0
(
m
o
d
[
m
1
,
m
2
]
)
x\equiv x_0\pmod{[m_1,m_2]}
x≡x0(mod[m1,m2]) (
[
m
1
,
m
2
]
[m_1,m_2]
[m1,m2] 指
l
c
m
(
m
1
,
m
2
)
lcm(m_1,m_2)
lcm(m1,m2) )
一路合并最后得到一个方程,方程右边就是解。
NTT模数
常用的几个模数(最小正原根皆为 3 )
- 469762049
- 998244353
- 1004535809
-
1997585853
\small{\colorbox{#000000}{\color{black}1997585853}}
1997585853划掉以防我记混,实际上一般记住三个就够了
如果现场忘了(也许)也可以打表,枚举
k
k
k 找
p
=
r
2
k
+
1
p=r2^k+1
p=r2k+1
任意模数NTT
有时候遇到 NTT 题却不给常规的 NTT 模数
比如猫猫可能会给你一个 998244853
长度为
n
n
n 的卷积模数为
m
m
m 那么最后得到的不取模的答案显然不超过
n
m
2
nm^2
nm2
就可以拆开
{
x
≡
a
1
(
m
o
d
p
1
)
x
≡
a
2
(
m
o
d
p
2
)
x
≡
a
3
(
m
o
d
p
3
)
\begin{cases} x\equiv a_1\pmod{p_1}\\ x\equiv a_2\pmod{p_2}\\ x\equiv a_3\pmod{p_3} \end{cases}
⎩⎪⎨⎪⎧x≡a1(modp1)x≡a2(modp2)x≡a3(modp3)
但是直接搞的话模数会爆炸
一个方法是先合并前两个得到
x
≡
A
(
m
o
d
M
)
x\equiv A\pmod{M}
x≡A(modM)
有
x
≡
k
M
+
A
(
m
o
d
m
)
x\equiv kM+A\pmod{m}
x≡kM+A(modm)
且
k
M
+
A
≡
a
3
(
m
o
d
p
3
)
kM+A\equiv a_3\pmod{p_3}
kM+A≡a3(modp3) 那么
k
≡
(
a
3
−
A
)
M
−
1
(
m
o
d
p
3
)
k\equiv(a_3-A)M^{-1}\pmod{p_3}
k≡(a3−A)M−1(modp3) 代入上去
解得。
注意在这个过程中(合并前两个同余方程以后),乘法要全程用龟速乘法取模
以免爆 __int64
不过它跑得巨慢
MTT
double 的精度可以稳定承受
1
0
14
10^{14}
1014
所以把系数都拆成
2
15
a
+
b
2^{15}a+b
215a+b
(
2
15
A
+
B
)
(
2
15
C
+
D
)
=
2
30
A
C
+
2
15
(
A
D
+
B
C
)
+
B
D
(2^{15}A+B)(2^{15}C+D)=2^{30}AC+2^{15}(AD+BC)+BD
(215A+B)(215C+D)=230AC+215(AD+BC)+BD
这样的话最多大约是
2
30
×
1
0
5
2^{30}\times 10^5
230×105 ,一般会用到 MTT 的题最多也就是这样。
然后带上共轭优化可以优化常数 八次FFT降到四次
还可以降到3.5次(没必要
分治FFT(不取模)
f
(
n
)
=
∑
i
=
1
n
f
(
n
−
i
)
g
(
i
)
f(n)=\sum\limits_{i=1}^nf(n-i)g(i)
f(n)=i=1∑nf(n−i)g(i)
换句话说也就是由
∑
i
=
0
n
f
(
i
)
g
(
n
−
i
)
=
0
\sum\limits_{i=0}^nf(i)g(n-i)=0
i=0∑nf(i)g(n−i)=0 推来的。
实际上可以解决
f
(
n
)
=
a
f
(
n
−
b
)
+
c
+
∑
i
=
1
n
d
f
(
n
−
i
)
g
(
i
)
f(n)=af(n-b)+c+\sum\limits_{i=1}^ndf(n-i)g(i)
f(n)=af(n−b)+c+i=1∑ndf(n−i)g(i)
怎么做?
如果对每个
f
(
n
)
f(n)
f(n) 都 FFT 的话不如直接暴力乘法
分治,每一层对右边的点 x ∈ ( M i d , R ] x\in(Mid,R] x∈(Mid,R] 只考虑左边的贡献 ω x = ∑ i = L M i d f ( i ) g ( x − i ) \omega_x=\sum\limits_{i=L}^{Mid}f(i)g(x-i) ωx=i=L∑Midf(i)g(x−i)
注意分治的时候要按照
递归左子区间 → 当前(算好左边对右边的贡献) → 递归右子区间
的顺序来进行。
分治FFT(取模)
f
(
n
)
≡
∑
i
=
1
n
f
(
n
−
i
)
g
(
i
)
(
m
o
d
p
)
f(n)\equiv\sum\limits_{i=1}^nf(n-i)g(i)\pmod{p}
f(n)≡i=1∑nf(n−i)g(i)(modp)
生成函数。
F
=
F
⊗
G
−
f
(
0
)
g
(
n
)
F=F\otimes G-f(0)g(n)
F=F⊗G−f(0)g(n)
F
⊗
(
1
−
G
)
≡
f
(
0
)
g
(
n
)
(
m
o
d
p
)
F\otimes (1-G)\equiv f(0)g(n)\pmod{p}
F⊗(1−G)≡f(0)g(n)(modp)
F
≡
(
1
−
G
)
−
1
f
(
0
)
g
(
n
)
(
m
o
d
p
)
F\equiv (1-G)^{-1}f(0)g(n)\pmod{p}
F≡(1−G)−1f(0)g(n)(modp)
多项式求逆。
FWT
离散卷积:
c
k
=
∑
i
∘
j
=
k
a
i
b
j
c_k=\sum\limits_{i\circ j=k}a_ib_j
ck=i∘j=k∑aibj