多项式模板学习笔记

多项式乘法

存在多项式 \(F(z)=\sum_{i=0}^na_iz^i,G(z)=\sum_{i=0}^mb_iz^i\),我们定义多项式乘法:

\[F(z)*G(z)=\sum_i\sum_ja_ib_jz^{i+j} \]

多项式的点值表达

一个 \(n\) 次函数可以用平面上的 \(n+1\) 个点来表达。

所以我们可以把一个 \(n\) 次多项式从 系数表达 转化成 \(n+1\) 个点来表达,这一步也叫 求值

然后如果 \(F(z)\)\((x_1,y_1)\)\(G(z)\)\((x_1,y_2)\),那么 \((F*G)(x_1)=y_1y_2\)

所以我们只需要在 \(F,G\) 上各寻找 \(\deg F+\deg G+1\) 个点即可确定 \(F*G\)

我们变成了 用系数找出点值表达用点值表达表达出系数

FFT

FFT 可以在 \(O(n\log n)\) 时间复杂度内解决多项式乘法。

DFT

我们先考虑如何找出 \(n+m+1\) 个点值。

前置知识:单位根

单位根 / \(n\) 次单位根:即 \(n\) 次幂为 \(1\) 的复数,用 \(w_n\) 表示

显然 \(n\) 次单位根共\(n\)个,写作\(w^k_{n}\) 的形式

根据 复数乘法模长相乘,幅角相加的法则,发现单位根只存在于半径为\(1\)单位圆

\(n\) 次单位根将此单位圆 \(n\) 等分

然后单位根有有如下性质:

  • \(w_0^n=1\)
  • \(w^{i}_nw^j_n=w^{i+j}_n\)
  • \(w^{ak}_{an}=w^{k}_{n}\)
  • \(w^{k+\frac n2}_n=-w^{k}_n(n\equiv 0(\bmod 2))\)

我们考虑一个 \(n\) 项多项式 \(F(z)=\sum_{i=0}^{n-1}a_iz^i\),然后我们把 \(n\) 补成 \(2\) 的次幂,所以可以平均分开。

得到:

\[F(z)=\sum_{k=0}^{(n-1)/2}a_{2k}z^{2k}+a_{2k+1}z^{2k+1} \]

\(FL(z)=\sum_{i=0}^{(n-1)/2}a_{2i}z^i,FR(z)=\sum_{i=0}^{(n-1)/2}a_{2i+1}z^i\)

显然我们可以发现:

\[F(z)=FL(z^2)+zFR(z^2) \]

我们代入一个 \(w^k_n,w^{k+\frac n 2}_n(k<\frac n 2)\),得到:

\[\begin{aligned} F(w^k_n)&=FL(w^{k}_{n/2})+w^{k}_nFR(w^k_{n/2})\\ F(w^{k+n/2}_n)&=FL(w^k_{n/2})+w^{k+n/2}_nFR(w^k_{n/2})\\ F(w^{k+n/2}_n)&=FL(w^k_{n/2})-w^{k}_nFR(w^k_{n/2})\\ \end{aligned} \]

所以如果我们只需要知道 \(FL,FR\)\(w^0_{n/2},w^1_{n/2},w^2_{n/2},\cdots w^{n/2-1}_{n/2},\) 处的点值表达即可,然后可以 \(O(n)\) 的得到 \(F(z)\)\(w^0_{n},\cdots w^{n-1}_n\) 处的点值。

然后我们分治下去即可,时间复杂度 \(T(n)=2T(\frac n 2)+O(n)=O(n\log n)\)

然后我们考虑点值转为系数表达。

IDFT

我们现在得到了一大堆点值,现在要把他转化成系数。

结论是我们用 \(w^{-1}_n\) 代替 \(w^1_n\) 做上面的部分然后除以 \(n\) 即可。

证明:我们设 \(G=\text{DFT}(F)\),那么我们知道

\[G_k=\sum_{i=0}^{n-1}F_i(w^k_n)^i \]

我们需要证明:

\[\begin{aligned} F_k&=\frac 1 n(\sum_{i=0}^{n-1}G_i(w_n^{-k})^i)\\ &=\frac1 n\sum_{i=0}^{n-1}(w^{-k}_n)^i\sum_{j=0}^{n-1}F_j(w^i_n)^j\\ &=\frac1 n\sum_{j=0}^{n-1}F_j\sum_{i=0}^{n-1}w^{i(j-k)}\\ j= k,ans&=\frac {nF_j}{n}=F_k\\ j\not=k,ans_j&=\frac {F_j} n\sum_{i=0}^{n-1}w^{ij}\\ &=\frac {F_j} n\times \frac {1-w^{jn}}{1-w^j}=0\\ \therefore \frac1 n\sum_{j=0}^{n-1}F_j\sum_{i=0}^{n-1}w^{i(j-k)}&=F_k\\ \end{aligned} \]

至于邪恶的蝴蝶变换,这个可以自己手玩得到。

破除封建迷信:STL 的 complex 跑的很快,根本不需要手写。

三次变两次

我们设 \(P=F+Gi\),那么我们得到 \(P^2=F^2-G^2+2FGi\),这样我们只用做一次 DFT 和一次 IDFT 即可。

三次变两次不掉精度。

MTT

系数过大的情况下,FFT 会有相当程度的精度误差。

我们把 \(F(x),G(x)\) 分别拆成 \(A(x)+cB(x),C(x)+cD(x)\),然后我们构造函数 \(T(x)=C(x)+D(x)i\)

然后我们要得到 \(A(x)C(x)+c(A(x)D(x)+B(x)C(x))+c^2B(x)D(x)\)

然后我们可以用 \(A(x)T(x),B(x)T(x)\) 得到 \(A(x)C(x)+A(x)D(x)i\)\(B(x)C(x)+B(x)D(x)i\)

然后就能用 \(3\) 次DFT 和 \(2\) 次 IDFT 解决问题。

NTT

就是用 \(g^{(p-1)/n}_n\) 代替 \(w^1_n\)

多项式牛顿迭代

主要是解决以下问题。

给出函数 \(g(x)\),求出一个 \(f(x)\),使得

\[g(f(x))\equiv 0(\bmod x^n) \]

我们递归考虑,假设我们已经知道 \(t(x)\),使得:

\[g(t(x))\equiv 0(\bmod x^{\lceil \frac n 2\rceil}) \]

那么我们知道

\[f(x)-t(x)\equiv 0(\bmod x^{\lceil \frac n 2\rceil}) \]

我们考虑将 \(g(x)\)\(t(x)\) 处泰勒展开,我们得到:

\[\begin{aligned} g(f(x))&=\sum_{n\ge 0}\frac {g^{(n)}(t(x))}{n!}(f(x)-t(x))^n\\ g(f(x))&\equiv g(t(x))+g'(t(x))(f(x)-t(x))+\sum_{n\ge 2}\frac {g^{(n)}(t(x))}{n!}(f(x)-t(x))^n(\bmod x^n) \end{aligned} \]

后面那一截等于 \(0\),所以我们知道:

\[\begin{aligned} g(f(x))&\equiv g(t(x))+g'(t(x))(f(x)-t(x))(\bmod x^n)\\ 0&\equiv g(t(x))+g'(t(x))(f(x)-t(x))(\bmod x^n)\\ f(x)&\equiv t(x)-\frac {g(t(x))}{g'(t(x))} \end{aligned} \]

然后递推求解即可。

多项式求逆

给定多项式 \(A(x)\),求解多项式 \(B(x)\),使得 \(A(x)B(x)\equiv 1(\bmod x^n)\)

考虑令 \(G(z)=\frac 1 z-A(x)\),那么 \(G'(z)=-\frac 1 {z^2}\),所以我们得到:

\[F(x)=t(x)-\frac {\frac 1 {t(x)}-A(x)}{-\frac 1 {t(x)^2}}=(2-A(x)t(x))t(x) \]

多项式开根

给定多项式 \(A(x)\),求解多项式 \(B(x)\),使得 \(B^2(x)\equiv A(x)(\bmod x^n)\)

我们考虑令 \(G(z)=z^2-A(x)\),则我们知道 \(G'(z)=2z\),所以我们知道 \(F(x)=t(x)-\frac {t^2(x)-A(x)}{2t(x)}=\frac {A(x)+t^2(x)}{2t(x)}\)

然后倍增求解即可,时间复杂度 \(T(n)=T(\frac n2)+O(n\log n)=O(n\log n)\)

多项式 ln

给定多项式 \(A(x)\),求解多项式 \(B(x)\),使得 \(B(x)\equiv \ln A(x)(\bmod x^n)\)

\[\begin{aligned} \ln A(x)&=\int (\ln A(x))'\\&=\int \frac {A'(x)}{A(x)} \end{aligned} \]

多项式 exp

给定多项式 \(A(x)\),求解多项式 \(B(x)\),使得 \(B(x)\equiv \exp A(x)(\bmod x^n)\)

考虑牛顿迭代,设 \(G(z)=\ln z- A(x)\),则 \(G'(z)=\frac 1 z\),所以我们得到:

\[\begin{aligned} F(x)=t(x)-\frac {\ln t(x)-A(x)}{\frac 1 {t(x)}}=(1-\ln t(x)-A(x))t(x) \end{aligned} \]

倍增求解即可,时间复杂度为 \(O(n\log n)\)

多项式快速幂

给定多项式 \(A(x)\),常数 \(k\),求解多项式 \(B(x)\),使得 \(B(x)\equiv A^k(x)(\bmod x^n)\)

\[\begin{aligned} A^k(x)=\exp (k\ln A(x)) \end{aligned} \]

\(O(n^2)\) 多项式操作

由于 shaber FFT 是高贵的 10 级考点,所以我们如果不想背那个 shaber 东西就用 \(O(n^2)\) 多项式操作吧。

可能在集合幂级数上可以使用。

多项式乘法

直接做即可。

多项式求逆

\[\begin{aligned} b_0&=\frac1 {a_0}\\ \sum_{i=0}^na_ib_{n-i}&=0\\ b_n&=-\frac 1 {a_0}\sum_{i=1}^na_ib_{n-i} \end{aligned} \]

多项式 \(\ln\)

\[\begin{aligned} \ln A(x)&=\int (\ln A(x))'\\&=\int \frac {A'(x)}{A(x)} \end{aligned} \]

多项式 \(\exp\)

\[\begin{aligned} B(x)&=\exp A(x)\\ B(x)'&=(\exp A(x))A'(x)\\ B(x)'&=B(x)A'(x) \end{aligned} \]

两边提取系数即可。

多项式快速幂

\[\begin{aligned} B(x)&=A^k(x)\\ B(x)'&=kA^{k-1}(x)A'(x)\\ B(x)'A(x)&=kB(x)A'(x)\\ \sum_{i=0}^n(i+1)b_{i+1}a_{n-i}&=k\sum_{i=0}^nb_i(n-i+1)a_{n-i+1}\\ \sum_{i=1}^{n+1}ib_{i}a_{n+1-i}&=k\sum_{i=0}^nb_i(n-i+1)a_{n-i+1}\\ \sum_{i=1}^{n}ib_{i}a_{n-i}&=k\sum_{i=0}^{n-1}b_i(n-i)a_{n-i}\\ b_n&=\frac 1{na_0}(k\sum_{i=0}^{n-1}b_i(n-i)a_{n-i}-\sum_{i=1}^{n-1}ib_ia_{n-i}) \end{aligned} \]

提取系数递推即可。

Boston-mori 算法

对于两个 \(k\) 次多项式 \(F(z),G(z)\),我们可以在 \(O(k\log k\log n)\) 的时间复杂度内求出

\[[z^n]\frac {F(z)}{G(z)} \]

\[\begin{aligned} Ans=[z^n]\frac {F(z)G(-z)}{G(z)G(-z)}\\ =[z^n]\frac {c_{even}(z^2)+xc_{odd}(z^2)}{v(z^2)}\\ \end{aligned} \]

如果 \(n=1(\bmod 2)\) 的话,\(Ans=[z^{n/2}]\frac {c_{odd}(z)}{v(z)}\)

否则 \(Ans=[z^{n/2}]\frac {c_{even}(z)}{v(z)}\)

所以我们只需要 \(O(\log n)\) 次多项式乘法即可。

Chirp Z

\[\begin{aligned} f(c^i)&=\sum_{j=0}^{n-1}a_jc^{ij}\\ f(c^i)&=\sum_{j=0}^{n-1}a_jc^{\binom {i+j}2-\binom i 2-\binom j 2}\\ f(c^i)&=c^{-\binom i 2}\sum_{j=0}^{n-1}a_j c^{-\binom j 2} c^{\binom {i+j}2}\\ \end{aligned} \]

减法卷积即可,\(\mathcal O(n\log n)\)

多项式连续点值平移

\[f(m+i)=(m+i)^\underline {n+1}\sum_{j=0}^n\frac {f(j)(-1)^{n-j}}{j!(n-j)!}\times \frac 1 {m+i-j} \]

\[a_j=\frac {f(j)(-1)^{n-j}}{j!(n-j)!},b_{n+i-j}=\frac {1}{m+i-j},b_j=\frac {1}{m-n+j} \]

然后我们知道:

\[f(m+i)=(m+i)^\underline {n+1}[z^{n+i}]A(z)B(z) \]

\(\mathcal O(n\log n)\)

多项式复合逆

已知多项式 \(F(z)\)\([z^0]F(z)=0,[z^1]F(z)\not= 0\),求 \(G(z)\) 使得 \(G(F(z))=z\)

考虑拓展拉反:

\[[z^n]H(G(z))=\frac 1 n[z^{n-1}](\frac {z}{F(z)})^nH'(z) \]

所以我们得到:

\[\begin{aligned} [z^n]F(z)^i&=\frac 1 n[z^{n-1}](\frac z {G(z)})^n(z^i)'\\ \frac n i[z^n]F(z)^i&=[z^{n-i}](\frac z {G(z)})^n\\ \end{aligned} \]

如果我们得到了 \((\frac z {G(z)})^n\) ,那么我们可以简单求出 \(G\),现在问题变成

\[[z^n]F^i(z),0\le i\le n \]

我们考虑有一个经典的东西是:

\[\sum_{i\ge 0}F^i(z)=\frac 1 {1-F(z)} \]

由于这会让各种次数的浙西混在一起,我们考虑引入第二元 \(y\),变成求解:

\[[z^n]\sum_{i\ge 0}F^i(z)y^i=[z^n]\frac 1 {1-F(z)y} \]

然后我们考虑 Bostan-Mori 求解分式远处求值问题。

我们发现每一次 \(x\) 次数减半, \(y\) 次数加倍,所以项数乘积一直是 \(O(n)\) 的,复杂度为 \(O(n\log^2 n)\)

转置原理

这个很有用的,也许你可以去学习

大概是对于我们需要求 \(M{\bf v}\) ,假设我们有方便的算法 \(\mathcal B\) 求出 \(M^T\bf v\),那么我们将 \(\mathcal B\) 的算法流程转置即可在几乎不改变时间复杂度的情况下求得 \(M\bf v\)

多项式多点求值

显然我们想要求出

\[\begin{bmatrix} 1 & a_0 & \cdots & a_{0}^n \\ 1 &\ddots & \vdots & a_1^n \\ \vdots &\vdots & \ddots & \vdots \\ 1 & \cdots & \cdots & a_{n}^n \end{bmatrix} \times \begin{bmatrix} f_0\\ f_1 \\ \vdots \\ f_n \end{bmatrix} \]

我们考虑转置:

\[\begin{bmatrix} 1 & 1 & \cdots & 1 \\ a_0 &\ddots & \vdots & a_n \\ \vdots &\vdots & \ddots & \vdots \\ a_0^n & \cdots & \cdots & a_{n}^n \end{bmatrix} \times \begin{bmatrix} f_0\\ f_1 \\ \vdots \\ f_n \end{bmatrix} \]

然后这个东西我们发现其生成函数就是:

\[\sum_{i=0}^n\frac {f_i}{1-a_ix} \]

所以 \(\mathcal B\) 就是分治 NTT 。

然后我们考虑 \(\mathcal B^T\),我们将转移顺序倒序,再改变贡献的方向即可。

比如对于 \(c_{i+j}\gets \sum a_ib_j\),转置后得到:

\[a_i=\sum c_{i+j}b_j \]

减法卷积即可。

posted @ 2024-05-04 10:26  Nityacke  阅读(50)  评论(0)    收藏  举报