简单的看了一下优化多项式常数的东西:source,实现了一下第一部分,这部分比较简单
大体的思路:
- 两个精度为 \(n\) 的多项式相乘时,可以预先尝试推导最终结果的前 \(n\) 项系数,改变式子形态消除贡献,做长 \(n\) 的循环卷积
- 消除贡献后去掉多余无贡献部分
- 将 \(f_0/f_0\) 或 \(f_0/f\) 一类的形态改变成 \(f_0g_0\),其中 \(g_0\equiv 1/f_0\pmod{x^{n}}\)
以下用无下标的代表模 \(x^{2n}\) 意义下,带下标 \(0\) 的代表模 \(x^n\) 意义下
用 \(\textsf E(n)\) 表示一次长度为 \(n\) 的 FFT 所需时间,例如两个精度为 \(n\) 的多项式相乘需要 \(6\textsf E(n)\),做长度为 \(2n\) 的循环卷积也需要 \(6\textsf E(n)\)
求逆与除法
即 \(h\equiv f/g\),直接做需要对 \(g\) 求长 \(2n\) 的逆,已经达到了 \(24\textsf{E}(n)\),重新审视递推式:
\[ \begin{aligned} h-h_0&\equiv 0&\pmod{x^n} \\ h^2-2hh_0+h_0^2&\equiv 0&\pmod{x^{2n}} \\ fh-2fh_0+gh_0^2&\equiv 0&\pmod{x^{2n}} \\ h&\equiv h_0-\left(\dfrac{g}{f}h_0^2-h_0\right) &\pmod{x^{2n}} \end{aligned} \]
我们希望将 \(f\) 用 \(h_0\) 中的 \(f_0\) 处理掉,注意进行长 \(2n\) 的卷积时,\(h_0\equiv f_0/g_0+\Delta_1 \pmod{x^{2n}}\),其中 \({\rm ord}(\Delta_1)\geq n\),因此:
\[ \begin{aligned} \dfrac{g}{f}h_0^2-h_0 \equiv \left(\dfrac{f_0}{f}gh_0 -f_0\right)\dfrac{1}{g_0} +\left(1-\dfrac{g}{f}h_0\right)\Delta_1 &\pmod{x^{2n}} \end{aligned} \]
而 \({\rm ord}(1-(g/f)h_0)\geq n\),因此 \(\Delta_1\) 不会做任何贡献
\(f_0/f\) 的后 \(n\) 项也会参与贡献,不妨令 \(f_0/f\equiv 1+\Delta_2\),\(f_1\) 代表 \(f-f_0\):
\[ \begin{cases} (f_0+f_1)\dfrac{1}{f}\equiv 1 \\ \dfrac{f_0}{f}\equiv 1+\Delta_2 \end{cases} \quad \Rightarrow\quad \Delta_2\equiv-\dfrac{f_1}{f} \]
\[ \dfrac{f_0}{f}gh_0 -f_0\equiv gh_0-f_0-\dfrac{f_1}{f}gh_0 \]
因为 \({\rm ord}(f_1)\geq n\),\(gh_0/f\) 的精度只需要达到 \(n\) 就可以了,这一部分显然为 \(1\),最终:
\[ h\equiv h_0-(gh_0-f)\dfrac{1}{g_0} \pmod{x^{2n}} \]
- 用长 \(n\) 的多项式乘法计算 \(h_0\):\(6\textsf{E}(n)\)
- 用长 \(2n\) 的循环卷积计算 \(gh_0-f\):\(12\textsf{E}(n)\);
- 长 \(n\) 的求逆计算 \(1/g_0\):\(12\textsf{E}(n)\)
故模 \(x^n\) 意义下计算 \(h\) 需要 \(15\textsf{E(n)}\)
在倒数的计算过程中,\(h_0\) 和 \(1/g_0 \pmod{x^{n}}\) 是一回事,于是我们不再需要计算 \(h_0\),同时每次迭代完成后求出的就是 \(1/g_0\pmod{x^{n}}\),因此从模 \(x^n\) 到模 \(2^n\) 我们仅需要 \(12\textsf{E}(n)\)
但是求逆我们需要从模 \(x^2\) 开始迭代,于是总时间依然是 \(12\textsf{E}(n)\)
exp
求 \(F\) 满足 \(G\circ F\equiv 0\) 我们想让 \(\sum a_n(F-F_0)^n\) 贡献出 \(G\circ F\),那就将其在 \(F_0\) 处泰勒展开,考虑到 \({\rm ord}(F-F_0)\geq n\),那么 \((F-F_0)\) 在平方项中就已经不可能向 \(F\) 贡献,即:
\[ \begin{aligned} &G\circ F\equiv G\circ F_0+(G^\prime \circ F_0)(F-F_0)\equiv 0 \\ \Rightarrow\quad&(G^\prime \circ F_0)F_0-G\circ F_0\equiv (G^\prime \circ F_0)F \\ \Rightarrow\quad&F\equiv F_0-\dfrac{G\circ F_0}{G^\prime \circ F_0} \end{aligned} \]
\(g\equiv \exp f\Rightarrow \ln g-f\equiv 0\),那么 \(G(x)\equiv \ln x-f,G ^\prime\equiv 1/x\)
此时:
\[ g\equiv g_0-g_0\int\left( \dfrac{g_0 ^\prime}{g_0} -f ^\prime\right) \]
直接做的话,我们要求 \(g ^\prime_0/g_0\) 要有 \(2n\) 的精度,于是我们要对 \(g_0\) 求长 \(2n\) 的逆,而这已经达到了 \(24\textsf{E}(n)\)
我们依然期望能将 \(g ^\prime_0/g_0\) 转化成 \(g_0 ^\prime h_0\),其中 \(h_0\equiv 1/g_0 \pmod{x^n}\)
于是观察 \({\rm ord}\):\({\rm ord}(g_0h_0 -1)\geq n,{\rm ord}(g_0 ^\prime/g_0-f ^\prime)\geq n-1\),于是对积分号内部分乘 \(g_0h_0\) 不会有任何影响,于是:
\[ \begin{aligned} \dfrac{g_0 ^\prime}{g_0} -f ^\prime \equiv \dfrac{g_0}{g_0}g_0 ^\prime h_0-g_0h_0 f ^\prime\equiv g_0 ^\prime h_0-f ^\prime-(g_0h_0-1)f_0 ^\prime \end{aligned} \]
其中 \(g_0/g_0\) 的精度达到 \(2n\) 视为 \(1\),后边 \(f-f_0\) 不会有贡献所以写成 \(f_0\)
- 用长 \(n\) 的循环卷积计算 \(g_0h_0-1,g_0 ^\prime h_0-f ^\prime\):\(6\textsf E(n)\)
- 用长 \(2n\) 的循环卷积计算剩余两次乘法:\(12\textsf{E}(n)\)
- 用长为 \(n\) 的求逆计算 \(h_0\):\(12\textsf{E}(n)\)
注意到 \(h_0\) 可以随着 \(\exp\) 的迭代而迭代,且 \(h_0\) 最后一次不需要迭代,因此总时间花费为 \(12+6+6=24\textsf E(n)\)
开根
\[ g\equiv g_0-\dfrac{(g_0^2-f)h_0}{2}\pmod{x^{2n}} \]
- 用长 \(n\) 的求逆计算 \(h_0\):\(12\textsf E(n)\)
- 用长为 \(n\) 的循环卷积计算 \(g_0^2-f\):\(3\textsf{E}(n)\)
- 用长为 \(2n\) 的循环卷积计算 \((g_0^2-f)h_0\):\(6\textsf{E}(n)\)
故花费 \(21\textsf{E}(n)\),依然注意到 \(h_0\) 也可以随着这个过程迭代,并且最后一轮对 \(h_0\) 的迭代可以省去,求逆过程常数变为原来的 \(1/2\),故共需要 \(15\textsf E(n)\)
1 | namespace Poly { |