多项式多点求值

· · 个人记录

给一 n 次多项式 F(x)m 次询问,每次求 F(x_i) 的值。

1 \le n,m \le 64000

EI,rqy

方法:转置原理

通过调整(补常数项,补询问),我们能够让 n=m

接下来可能会用到许多线性代数的东西。

好的让我们进入正题。

我们要求的是这样的一个矩阵(列向量):

\begin{pmatrix} 1& x_0& x_0^2& \cdots& x_0^{m-1}\\ 1& x_1& x_1^2& \cdots& x_1^{m-1}\\ 1& x_2& x_2^2& \cdots& x_2^{m-1}\\ \vdots& \vdots& \vdots& \ddots& \vdots\\ 1& x_{n-1}& x_{n-1}^2& \cdots& x_{n-1}^{m-1}\\ \end{pmatrix} f

其中 x_i 为要求的第 i 个点值,在这里我们认为它是固定的,即与 f 无关的。f 为输入的系数向量(列矩阵)

其中左边的叫做范德蒙矩阵,记作 V。我们发现 Vf 并不好求,但是 V^Tf 很好求,即:

\mathbf V(x_0, x_1,\dots, x_{n-1})^{\mathsf T} \mathbf f = \begin{bmatrix} 1& 1& 1& \cdots& 1\\ x_0& x_1& x_2& \cdots& x_{n-1}\\ \vdots& \vdots& \vdots& \ddots& \vdots\\ x_0^{n-1}& x_1^{n-1}& x_2^{n-1}& \cdots& x_{n-1}^{n-1} \end{bmatrix}\mathbf f

很好求。为什么呢?我们仔细观察,发现这个东西用多项式来表达为:

\sum_{i=0}^n f_i\sum_{j=0}^n x_i^jx^j\\ =\sum_{i=0}^nf_i\frac{1}{1-x_ix}

这个东西可以通过分治套 NTT 暴力通分搞出分子和分母,然后多项式求逆得到答案。复杂度为 O(n \log^2 n)。然而这样做一定是假的,因为它求出的是 V^Tf,这个没有任何意义。但是这个求 V^T 的过程对求 V 的过程很有启发。

考虑到 (V^T)^T=V ,我们只需要把刚才那个“假”做法中的所有初等行变换记录下来,反过来乘其置换矩阵即可。但是太麻烦了。我们考虑这个操作在我们人类眼中是个什么样子的存在。

首先分解 V^Tf。我们那个假做法为:[除以分母] \times [分治NTT求分子] \times f,其中 [除以分母][分治NTT求分子] 都可以看作矩阵。

具体地讲,我们设常多项式 g(x) = \prod_i 1-x_ix,即分母,那么 [除以分母] 这个操作实际上为 [IDFT] \times [与 g^{-1} 对应位相乘] \times [DFT][分治NTT求分子] 这个操作比较复杂:

如果我们认为列向量 f 是由原来叶子上的一个个初值组成的,那么这些操作(主要是非叶节点的操作)都可以看作是对 f 的一系列线性变换。或者说,是若干多项式逐渐合并成为一个多项式的过程。

现在我们要探寻 V^T 的转置矩阵 (V^T)^T,它应该是:

(([IDFT] \times [对应乘g的点值] \times [DFT]) \times [自下而上递归求分子])^T\\ =[自上而下反过来变换]^T \times [DFT] \times [对应乘] \times [IDFT]

右面那部分比较好算,可以算得:

[DFT] \times [对应乘] \times [IDFT] \times f = h

现在考虑 [自上而下反过来变换]^T 究竟是什么:

这些操作可以看作是一个多项式逐渐分裂分裂变成一堆零次多项式,而那些零次多项式所组成的矩阵即为所求矩阵 Vf

于是一切都结束了。算法流程为: