$$
\Large\color{blue} Jhb\color{red}\text{的多项式浅谈}
$$
这个的后半部分似乎可以当做金策大佬论文的人话解读。
推销一下窝的博客,本文所有的代码都在窝的博客上。
多项式主要的用途是用来优化式子,因为笔者也刚刚入门多项式,可能谈到的内容也十分浅,有错请直接开 D。
我们从大整数乘法入手,我们经常写的算法是通过枚举两个整数的每一位,通过位权来更新答案,这里显然是 $O(n^2)$ 。还有一种是分治乘法,还是通过位权,原理是 :
$$
(Ax^m + B)(Cx^m + D) =ACx^{2m} + ((A + B)(C +D) - AC - BD))x^m + BD
$$
我们直接分治可以算出答案复杂度 $O(n^{2})$ 复杂度比较优秀?其实这种想法和之后的 MTT 优化是相同的。其中 n 表示位数。
复杂度怎么算? $T(n) = 4T(\frac{n}{2}) + O(n)$
$T(n) = O(n^2)$
之后我们考虑优化 $ACx^m + ((A - B)(D - C) + AC + BD) \times x^{\frac{n}{2}} + BD$ 这边只有 3 个乘积可以考虑优化 $T(n) = 3T(\frac{n}{2}) + O(n) = O(n^{\log_23})$ 可以接受。
主定理:
$$
T(n) = aT(\lceil\frac{n}{b}\rceil) = O(n^d)\
T(n) =
\begin{cases}
O(n^d), d > log_ba \
O(n^d \log n), d = log_b a\
O(n^{log_ba}), d < log_ba
\end{cases}
$$
但是我们可以我们 FFT 将系数表示法变成点值表示法,从而得到答案复杂度 $O(n \log n)$。
我们常用的表示法是系数表示法 $f(x) = \sum_{i = 0} a_i x^i $ 我们可以从中取 n + 1 个点来表示这个多项式,也就是 $f(x) = {a_0,a_1\dots a_n}$
DFT 就是把一个多项式从系数转化成点值,IDFT 反之。
FFT
对于两个个点值表示法的多项式 $f(x) = (x_0, f(x_0)) \dots (x_n, f(x_n))$ 和 $g(x) = (x_0, g(x_0)) \dots (x_n,g(x_n))$
设 $F(x) = f(x) \cdot g(x) = (x_0, f(x_0)g(x_0)) \dots (x_n, f(x_n)g(x_n))$ 可以看出我们能够快速得将其相乘。
但是直接暴力 DFT,IDFT 是 $O(n^2)$ 的,有些暴力还是用高斯消元。。。
我们发现 $x^i$ 在 $x = 1,-1$ 的时候是很简单的,这会让我们想到圆,之后我们需要 n + 1 个数,那么我们不妨用模长为 1 的复数。
$\omega_n = e^{\frac{2\pi i}{n}}$ 则 $x^n = 1$ 的解集为 ${\omega_n^k|k = 0,1\dots n - 1}$ 也就是将一个圆分成 n 等分。
$\omega_n = e^{\frac{2\pi i}{n}} = cos (\frac{2\pi}{n}) + i \cdot sin(\frac{2\pi}{n})$
$\text{单位圆}$
在一个复平面上,以原点为圆心, 1 为半径作圆,所得到的圆就是单位圆,将其 n 等分( n 等分点就是终点),形成 n 个向量,设幅角为正且最小的向量 $w_n$ ,称为 n 次单位根
剩下的复数为 $w_n^2 \dots w_n^n$
$w_n^0 = w^n_n = 1$
$w_n^k = \cos k \times \frac{2\pi}{n} + i \sin k \times \frac{2\pi}{n}$
单位根的幅角为周角的 $\frac{1}{n}$
$w_n^{\frac{n}{2} + k} = - w_n^k$
证明考虑将其展开 $w_n^{\frac{n}{2}} \times w_n^k$
将左边的那项展开得到 $-1$
$(w^k_n)^2 = w_{\frac{n}{2}}^k$
证明考虑,复数相乘,幅角相加,模长为 $1 \times 1 =1$ 因为都是单位根
$FFT$
首先我们先假设一个多项式的系数 假设 n 为偶数 $A(x) = (a_0,a_1,a_{n - 1})$
$$A(x)=a_0+a_1x+a_2{x^2}+a_3*{x^3}+a_4*{x^4}+a_5*{x^5}+ \dots+a_{n-2}*x^{n-2}+a_{n-1}*x^{n-1}$$
我们把它的下标按奇偶性分类
$$
\begin{cases}
A(x) = \sum_{i = 0} ^ {n -1} a_i x^i \
A_1(x) = \sum_{i = 0} ^ {m - 1} a_{2i} x^{2i} \
A_2(x) = \sum_{i = 0} ^ {m - 1}a_{2i + 1} x ^{2i + 1} \
m = \frac{n}{2}
\end{cases}
$$
所以我们可以得到
$A(x) = \sum_{i = 0} ^ {m - 1}a_{2i} (x^2) ^i + x\sum_{i = 0} ^ {m - 1} a_{2i + 1} (x^2) ^ i$
所以我们可以将其分成两部分进行递归,也就是 $A(x) = A_1(x^2) + x A_2(x^2)$
但是根据主定理,这是 $O(n^2)$
我们考虑 $A(w^k_n) = A_1((w_n^k)^2) + w_n^k A_1((w_n^k)^2)$
$(w_n^k)^2 = w_{\frac{n}{2}} ^ k$
所以可以化简
$$
\begin{aligned}
m &= \frac{n}{2} \
A(w_n^k) &= A_1(w_m^k) + w_n^kA_2(w^k_m) \
&\text{之后来看后半部分} \
A(w_n^{k + m}) &= A_1(w_m^k) - w_{n}^kA_2(w_m^k)
\end{aligned}
$$
发现只要知道了 RHS 就可以直接求出, 复杂度为 $O(n \log n)$
这叫蝴蝶变换
$IDFF$
这里就只想结论 $B(x) = \sum_{i = 0} ^ {n- 1} b_i \times x^i$ 在 $w_n^{ki}$
其中 $0 \le k < n$ 的点值
发现 $w_n^{-k}$ 与 $w_n ^ k$ 是对应的, $w_n^{-k} = w_n ^ {n + k}$
所以我们只要用 FFT 之后再将数组反过来就可以了
递归形式的 FFT
我们发现原来的每一个位置,在结束之后会变成其的反序
具体来说
1 | 原来的序列: 000 001 010 011 100 101 110 111 |
我们考虑求出最终的位置,之后再倒序回去,因为
1 | i 和 i / 2 的关系: |
$Code$
1 | for(int i = 0; i < lim; ++ i) |
最后我们考虑蝴蝶操作过程
$m = \frac{n}{2}$ 的所有值已经计算好并且放到 A 中了
$$
\begin{aligned}
A_1(w_m^k) &= A[k], A_1(w_m^k) = A[k + m] \
\Rightarrow A(w_m^k) &= A[k] + w_n^k \times A[k + m] \
\Rightarrow A(w_m^{k + m}) &= A[k] - w_n^k \times A[k + m]
\end{aligned}
$$
之后我们一层层向上递推就可以了
NTT
我们发现 FFT 的精度其实不是很够,最多处理 $10^8$ 的数据。我们考虑用什么东西来代替这个 FFT。这里有一个很好的替代品就是原根。对于质数 $p = qn + 1, n = 2^m$ 原根 $g$ 满足 $g^{qn} = 1 \pmod p$ 所以将 $g_n$ 看做 $\omega_n$ 也是可以的。
常用的模数是:
$$
p =
\begin{cases}
998244353 = 479 \times 2 ^{21} + 1, g = 3\
1004535809 = 7 \times 17 \times 2^{23} +1, g = 3\
469762049 = 7 \times 2^{26} + 1, g = 3
\end{cases}
$$
因为他们的原根都是 3。(这里的模数都是常在 3% NTT 中使用的)
$g^{qn} = e^{2\pi n}$ 我们如果迭代到长度 $l$ 的时候 $\omega_n = g_l = g_n^{\frac{n}{l}} = g_n^{\frac{p - 1}{l}}$
3 模数 NTT
我们考虑如果模数不支持 NTT 怎么办?我们可以自己定模数,只要保证答案符合(大于)范围即可。
其实很简单,就是用 3 个模数做一遍 NTT 之后 CRT 合并即可,用的就是之前说的模数。
MTT
我们考虑如果模数不支持 NTT 而且还卡常怎么办?虽然说 NTT 跑得很快,如果码力不行怎么办?用 MTT。
这里其实有点争议,就是 3% NTT 到底算不算 MTT。
本文只介绍一种最简单的,但是最常用的优化。
我们考虑进行 FFT 的时候我们用到了复数。那么我们为什么不把一个多项式的系数拆成几的部分分别进行处理,这样就可以保证精度。
假设我们要求 $P \times Q, P = \sum_{i = 0}p_ix^i, Q = \sum_{i = 1}q_ix^i$
我们考虑将系数拆成两部分
$ A = P_i >> 15, B = P_i & (32767) $
$C = Q_i >> 15, D = Q_i & (32767)$
$PQ=AC2^{30}+(AD+BC)*2^{15}+BD$
之后我们考虑通过复数来表示,设 $F = A + iB, G = C + i \times D$
这样我们可以先通过 FFT 之后再将其表示成答案的形式,最后在计算。
但是我们发现,需要表示之前的式子需要 $\overline{F}, \overline{G}$
$\overline{F}$ 表示 F 的共轭复数。
那么我们来证明一个东西。我们不妨记 $conj(x)$ 表示 x 的共轭复数。
用 $P_t$ 表示 P 的 DFT。
$$
\text{证明:P = A + iB, Q = A - iB}\
\color{red}\text{注意这里 P, Q 与之前的不同}
$$
$$
\begin{aligned}
p_t(x) =& A(w_n^k) + iB(w_n^k) \
=& \sum_{j = 0} ^ {n - 1} A_jw_n^{jk} + i B_jw_n^{jk} \
=& \sum_{j = 0} 6 {n - 1} (A_j + iB_j) w_n^{jk}\
\end{aligned}
$$
之后我们考虑能不能将 Q 用 P 表示出来,我们考虑将 Q 进行展开。
$$
\begin{aligned}
Q_t(x) =& Aw_n^k - iB(w_n^k) \
=& \sum_{j = 0} ^{n - 1} (A_j - iB_j) w_n^{jk} \
=& \sum_{j = 0} ^ {n - 1} (A_j - iB_j)\Bigg(cos\bigg(\frac{2\pi jk}{n}\bigg) + isin\bigg(\frac{2\pi jk}{n}\bigg)\Bigg) \
= & \sum_{j = 0} ^ {n - 1} A_jcos\bigg(\frac{2\pi jk}{n}\bigg) + B_j sin\bigg(\frac{2\pi jk}{n}\bigg) + i(A_jsin\bigg(\frac{2\pi jk}{n}\bigg) - B_jcos\bigg(\frac{2\pi jk}{n}\bigg)) \
= & conj(\sum_{j = 0} ^ {n - 1} A_jcos\bigg(\frac{-2\pi jk}{n}\bigg) + B_j sin\bigg(\frac{-2\pi jk}{n}\bigg) - i(A_jsin\bigg(\frac{-2\pi jk}{n}\bigg) - B_jcos\bigg(\frac{-2\pi jk}{n}\bigg))) \
= & conj(\sum_{j = 0} ^ {n - 1} (A_j + iB_j) \times (cos\bigg(\frac{-2\pi jk}{n}\bigg) - isin\bigg(\frac{-2\pi jk}{n}\bigg))) \
= & conj(\sum_{j = 0} ^ {n - 1} (A_j + iB_j)(w_n^{-jk}) \
= & conj(\sum_{j = 0}^{n - 1} (A_j + iB_j)(w_n^{-jk})) \
= & conj(P_t(n - k))
\end{aligned}
$$
这里有两个细节,我们一开始是将两个式子都展开,之后通过欧拉定理进行展开,猜测两个数是共轭质数。
这里变成共轭的时候,将 cos 部分变成负数。
我们考虑一个更加普通的形式对于一个 $w_n^k$ 的共轭复数是多少?将 $w_n^k$ 表示成 $a + ib$ 的形式,其共轭复数容易得到是 $a -i b$ 之后我们考虑在数轴上对应的是多少
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-pQ3sobeh-1618049627378)(https://z3.ax1x.com/2021/04/10/cabTrq.png)]]
可以发现其在轴上的对应点就是 $w_n^{ -k}$ 可以理解成,原来是向上数 k 的单位,现在是向下数。
之后将其展开也是同理,可以得到 $w_n^{-k} = cos(\frac{-2\pi k}{n}) + isin(\frac{-2\pi k}{n})$
但是我们计算答案的时候可没有负的指数,我们可以用 $n - k$ 来表示 $-k$ 因为圆上总共有 n 个点。
这样我们就证明了 $Q$ 可以由 $P$ 表示出来。
所以我们总共只需要进行 4 次 FFT 就可以得到答案了。
多项式求逆
我们需要求 $F \times Q \equiv 1 \pmod {x^n}$ 中的 $Q$。
考虑使用递归解决,假设我们已经得到 $Q_1 \times F \equiv 1 \pmod {x^\frac{n}{2}}$
我们需要求 $F \times Q \equiv 1 \pmod {x^n}$
可以得到 $F \times Q \equiv 1 \pmod {x^{\frac{n}{2}}}$
考虑将两个式子进行相减来消除 1
$$
F \times (Q - Q_1) \equiv 0 \pmod {x^{\frac{n}{2}}}
$$
因为 $F$ 肯定不是 0,所以考虑将其消掉,之后再考虑平方。
$$
(Q - Q_1) ^ 2 \equiv 0\pmod {x^n} \
Q^2 + Q_1^2 - 2QQ_1 \equiv 0 \pmod {x^n} \
Q + FQ_1^2 - 2Q_1 \equiv 0 \pmod {x^n} ,\text{这里两边乘了 F}\
Q \equiv 2Q_1 - FQ_1^2 \pmod {x^n}
$$
这样递归去做就可以了。
多项式 Ln
需要求 $Q \equiv \ln F \pmod {x^ n}$
我们考虑直接进行 exp 发现我们还没学过
那么能消去 Ln 的还有什么呢? 求导!
$Q’ \equiv \frac{F’}{F} \pmod {x^n}$
之后又手就行。
多项式 Exp
需要求 $Q \equiv e^F \pmod {x^n}$
我们优先考虑 Ln 转换成 $\ln Q \equiv F \pmod {x^n}$ 之后考虑进行牛顿迭代。
$$
\begin{aligned}
y &= f(x_0) + f’(x_0)(x - x_0) \
0 &= f(x_0) + f’(x_0)(x - x_0) \
0 &= f(x_0) - f’(x_0)x_0 + f’(x_0)\
x &= \frac{f’(x_0)x_0 - f(x_0)}{f’(x_0)}\
x &= x_0 - \frac{f(x_0)}{f’(x_0)}
\end{aligned}
$$
我们考虑将之前的式子变换得到 $\ln Q - F \equiv 0 $
我们设函数 $S(G) = \ln G - F$
然后考虑带入之前的式子
这里说明一下 $S’(G) = \frac{1}{G}$ 的原因,我们本质上是将整个 G 看成一个变量,而不是里面的每一个 $x^i$ 所以这里并不是符合函数求导。
$$
G = G_0 - \frac{\ln G_0 - F}{\frac{1}{G_0}} \
G = G_0 - G_0 \times (\ln G_0 - F)\
G = G_0 \times (1 - \ln G_0 + F)
$$
之后有手就行。
多项式开根
我们需要求 $F^2 = G$ 还是考虑递归,假设 $F_1^2 \equiv G \pmod {x^{\frac{n}{2}}}$
还是考虑消元
$$
F \equiv F_1 \pmod {x^{\frac{n}{2}}}\
F - F_1 \equiv 0 \pmod {x^{\frac{n}{2}}} \
F^2 + F_1^2 - 2FF_1 \equiv 0 \pmod {x^n} \
G F_1^2 - 2F_1F \equiv 0 \pmod {x^n} \
F \equiv \frac{G}{2F_1 + F_1^2} \pmod {x^n}
$$
还是很简单。
多项式除法
给定多项式 $F, G$ 求出多项式 $R, Q$ 使得 $F = G \times Q + R$。
其中 $F$ 的次数为 $n,G$ 的次数为 $m$。
可以想到如果没有余数的话,我们直接用多项式求逆就可以水掉。
因为这是个多项式,我们考虑将 R 给消掉,然后就可以与愉快得求逆了。
考虑构造 4 个多项式,满足 $F_1 = G_1 \times Q_1 + x^k R_1$ 这样子只要 $\mod x^k$ 就可以得到答案了。考虑构造这个多项式,为了让外面有 $x^k$ 这个系数,所以考虑将 $F(x)$ 变成 $F(\frac{1}{x})$。 可以知道变成这样之后的式子仍然是满足的,我们考虑两边同时乘以 $x^n$。
$x^nF(\frac{1}{x}) = x^{n}G \times Q + x^n R$ 我们考虑 $x^nF(\frac{1}{x})$ 的每一个系数其实等价于将原来的 F 给翻转一下的系数。那么我们不妨让 $F_1 = x^nF(\frac{1}{n}), Q_1 = x^mQ(\frac{1}{n})$ 其他同理。
那么我们得到 $F_1 = G_1 \times Q_1 + x^{n - m + 1}R_1$ 看出 $k = n - m + 1$。之后发现一个神奇的事情 $Q_1$ 的次数是 $n - m$ 所以我们即使 $\mod x^{n - m + 1}$ 也不会影响 $Q_1$。所以我们得到式子 $F_1(x) = G_1(x) \times Q_1(x) \mod x^{n - m + 1}$ 也就是 $Q_1(x) = \frac{F_1(x)}{G_1(x)}$。
之后我们求出了 $G_1$ 之后将其翻转一下就变成 $G$ 了,然后就可以得到 $R(x) = F(x) - G(x) \times Q(x)$。
很简单。
这边之后还会更新。