闲话
老师,数论会和 dp
有关吗?
“会的,而且如果有关的话也会比较简单”
开篇
FFT
和 NTT
都是用来求多项式的,他们可以求所有的 加法卷积,也就是形如 \(h_x=\sum\limits_{i+j=x}a_ib_j\)。那么显然我们的多项式乘法、以及一些 dp
式都具有卷积的特性。
初中老师都教过我们,如果是多个多项式相乘,我们可以拆括号,那么如果两个序列长度为 \(n\),\(m\),那么我们的计算量为 \(\mathcal O(nm)\)。
那么到 OI
里,有没有我们更快的算法呢?前面我们都讲过,OI
最大的乐趣,莫过于 \(\mathcal O(n^2)\rightarrow \mathcal O(n\log n)\)。
那么我们如何优化这种算法呢?
点值表示
我们假设我们有一个 \(n-1\) 次多项式,那么我们假设 \(y=\sum\limits_{i=0}^{n-1} a_ix^i\),那么我们显然有 \(n\) 个解 \(x_0,x_1,\cdots,x_{n-1}\),并且有对应的 \(y_0,y_1,\cdots,y_n\),那么我们将 \(<x_0,y_0>,<x_1,y_1>,\cdots,<x_{n-1},y_{n-1}>\) 记作点值。
那么我么假设我们随了几组特别强的 \(x_i\),那么当然 \(y_i\) 也会很强,我们考虑怎么确定这个多项式呢?
点值唯一定理
假设我们有不同的 \(x_i\),那么根据这些 \(<x_i,y_i>\) 我们可以逆推原多项式的 \(a_i\),即根据数值求系数,并且情况是 唯一的。
可以补充一下怎么求解。
我们写成矩阵形式,即:
以上为范德蒙德卷积形式,只要 \(<x_0,x_1,\cdots,x_{n-1}>\) 互不相同,就有唯一解,这就是 DFT
的过程。
我们可以给个简单的证明。我们将上面的矩阵写为行列式。
我们每一次用前一列乘上 \(x_0\) 然后消去,可以得到:
很好!让我们紧接着提取公因式,得到:
以此类推我们就找到了递推式!然后我们就可以发现,只要 \(x_i\) 互不相同,就不会有 \(0\),然后就有唯一解了。
非常好,所以现在我们只需要找到若干个点值就可以得到这个多项式的系数了,这就叫做 IDFT
。
但是这样是 \(\mathcal O(n^2)\) 的复杂度傻大,所以咋办呢?
DFT
单位根
我们发现上面的做法瓶颈是啥呢?是确定完了 \(n\) 个 \(x_i\) 后求数值,这样就是 \(\mathcal O(n)\times O(n)\),怎么办呢?
我们可以把目光放到 \(x_i\) 上,我们想有没有一些具有性质的数,能够降低复杂度呢?
答案是 单位根。
先来讲讲复数,我们定义 \(i=\sqrt{-1}\),而我们设 \(z=a+bi\),这就是一个复数了。复数的加减乘除和实数完全一致。
我们如果把普通平面直角坐标系放到复数系,那么我们就可以得到复平面的一个向量来表示复数。
我们可以表示 \(z=|z|(\cos\theta+i\sin\theta)\),\(|z|\) 表示模长。
我们可以简写为 \(z=e^{i\theta}\)
那么单位根是个啥东东呢?我们假设 \(\omega_n\) 为 \(n\) 次单位根,那么 \(\omega_n=\cos{\frac{2\pi}{n}}+i\sin{\frac{2\pi}{n}}\)。
然后我们可以发现一些规律。
- \(\omega_n^{\frac{n}{2}}=-\omega_n^0\)
- \(\omega_n=\omega_0\)
- \(\omega_{nk}^{kd}=\omega_{n}^d\)
- 折半定理:\(\forall n,k\in\{k|k=2y,y\in N\},\omega_n^k=\omega_{\frac{n}{2}}^{\frac{k}{2}}\)
- \(\sum\limits_{i=0}^{n-1} \omega_n^i=0\)
- \(\omega_n^k=\omega_n^{k\% n}\)
根据以上性质,我们就可以快速计算单位根的幂次,这样就不用 \(\mathcal O(n)\) 算值了,而是 \(\mathcal O(\log n)\) 次!
具体的,我们设 \(<\omega_n^0,\omega_n^1,\cdots,\omega_n^{n-1}>\),\(y=\sum\limits_{i=0}^{n-1}a_ix^i\),那么我们方便起见令 \(n=2^L-1\),也就是比它大的第一个 \(2\) 的幂次减一。
我们把 \(y\) 的多项式分为奇偶项(根据次数)。我们得到 \(y_i=(a_0+a_2\omega_n^{2i}+a_4\omega_n^{4i}+\cdots+a_{n-2}\omega_n^{(n-2)i})+\omega_n^i(a_1+a_3\omega_n^{2i}+\cdots+a_{n-1}\omega_n^{(n-2)i})\)。
根据折半定理,\(y_i=(a_0+a_2\omega_{\frac{n}{2}}^{i}+a_4\omega_{\frac{n}{2}}^{2i}+\cdots+a_{n-2}\omega_{\frac{n}{2}}^{\frac{(n-2)i}{2}})+\omega_n^i(a_1+a_3\omega_{\frac{n}{2}}^{i}+\cdots+a_{n-1}\omega_{\frac{n}{2}}^{\frac{(n-2)i}{2}})\)。
我们令 \(Y_1(\omega_{\frac{n}{2}}^{i})=a_0+a_2\omega_{\frac{n}{2}}^{i}+a_4\omega_{\frac{n}{2}}^{2i}+\cdots+a_{n-2}\omega_{\frac{n}{2}}^{\frac{(n-2)i}{2}}\),\(Y_2(\omega_{\frac{n}{2}}^{i})=a_1+a_3\omega_{\frac{n}{2}}^{i}+\cdots+a_{n-1}\omega_{\frac{n}{2}}^{\frac{(n-2)i}{2}}\),那么 \(y_i=Y_1(\omega_{\frac{n}{2}}^{i})+\omega_n^iY_2(\omega_{\frac{n}{2}}^{i})\)。
但是这样我们的 \(i\) 还是 \(n\) 的级别,怎么与 \(\frac{n}{2}\) 建立联系呢?
我们可以发现当 \(i\in [0,\frac{n}{2})\),我们就用 \(y_i=Y_1(\omega_{\frac{n}{2}}^{i})+\omega_n^iY_2(\omega_{\frac{n}{2}}^{i})\)。
对于 \(i\in[\frac{n}{2},n)\),我们可以 \(y_i=Y_1(\omega_{\frac{n}{2}}^{i-\frac{n}{2}})+\omega_n^{i-\frac{n}{2}}\omega_n^{\frac{n}{2}}Y_2(\omega_{\frac{n}{2}}^{i-\frac{n}{2}})\)。
大功告成!这样无论 \(i\) 取何值,我们都有 \(n\) 到 \(\frac{n}{2}\) 的映射了!
而我们发现 \(\omega_n^{n\frac{n}{2}=-1\),所以对于 \(i\in[\frac{n}{2},n)\),我们可以 \(y_i=Y_1(\omega_{\frac{n}{2}}^{i-\frac{n}{2}})-\omega_n^{i-\frac{n}{2}}Y_2(\omega_{\frac{n}{2}}^{i-\frac{n}{2}})\)。
我们对于 \(i\in [0,\frac{n}{2})\),可以这么写:
这样我们原来要求的是 \(y_0,\cdots,y_{n-1}\),现在我们只需要求 \({Y_1}_0,\cdots,{Y_1}_{\frac{n}{2}-1}\) 和 \({Y_2}_0,\cdots,{Y_2}_{\frac{n}{2}-1}\)。
根据主定理,这显然是 \(\mathcal O(n\log n)\)。