简单多项式学习笔记

离谱的多项式

——简单多项式和生成函数学习笔记

By Tuifei_oier

Part 1 前言

多项式和生成函数同属 OI 中数学方面的知识,在学习它们的过程中,不仅要掌握一些基础的对于它们本身的知识和操作,更要学会去通过构造和计算来解决相关的问题。
因此,本文先从定义入手记录一些多项式和生成函数的基础操作,再记录一些经典的应用和构造方式。

Part 2 科技篇

随便编的定义

首先,我们给出形式幂级数的定义:
对于形式幂级数 \(F(x)=\sum\limits_{i\ge0}a_ix^i\),我们不关心 \(x\) 的取值,也不关心它的收敛性等,仅仅关心它的各项系数。因此,对于形式幂级数,我们认为它可以进行任何变换而不受限制。例如:

\[\sum_{i\ge0}x^i=\dfrac{1}{1-x} \]

一般来说,当 \(x\in(0,1)\) 时左式收敛,于是等号成立。
但是对于形式幂级数,由于我们不关心 \(x\) 的值也不关心求和式最终的结果,所以等号何时都成立。

接下来,定义接下来讨论的多项式 \(F(x)=\sum\limits_{i=0}^na_ix^i\),它是一个 \(n\)形式多项式,即系数数列有限项的形式幂级数。在 OI 中,我们大部分情况下讨论形式多项式,即我们同样不关心 \(x\) 的具体取值。

一些表示:
\(F(x_0)\) 表示 \(x=x_0\)\(F(x)\) 的取值。
\(F_i\)\([x^i]F(x)\) 表示 \(F(x)\)\(x^i\) 项的系数。

多项式全家桶

首先是最基础的卷积,即:

\[H_{i+j}=\sum_{i=0}^n\sum_{j=0}^mF_iG_j \]

就是把两个多项式相乘,利用 FFT 可以 \(O(n\log n)\) 解决。


一维循环卷积,即:

\[H_{x}=\sum_{i+j\equiv x}F_iG_j \]

发现实际上 FFT 求的就是循环卷积,于是直接做之后把系数加到 \(\bmod\ n\) 后的位置上就好了。
对于二维循环卷积,即:

\[H_{x,y}=\sum_{i+j\equiv x}\sum_{k+l\equiv y}F_{i,k}G_{j,l} \]

我们可以先求出对于两边的矩阵做 DFT,然后对位相乘得到新矩阵再 IDFT 回去。
如何 DFT 一个矩阵呢?我们可以先把每一行看成一个多项式系数数列,然后把它们代表的多项式都 DFT,对得到的新矩阵的每一列再进行相同操作,最后就得到了原矩阵的 DFT 矩阵,IDFT 就是把整个操作逆向进行即可。
对于高维,同理。
关于循环卷积有一个重要的算法——Bluestein 算法。
因为在 DFT 和 IDFT 过程中都要求 \(n\)\(2\) 的若干次方;而当 \(n\) 不为 \(2\) 的次方时,我们要不一次一次暴力做,但这样可能会导致复杂度问题;或者,我们就可以利用这个算法。具体的说,对于长度为 \(n\) 的数列 \(A\),我们要求长度为 \(n\) 的数列 \(B\) 满足:

\[B_i=\sum_{j=0}^{n-1}x^{ij}A_j \]

\[=\sum_{j=0}^{n-1}x^{\frac{i^2+j^2-(i-j)^2}{2}}A_j \]

\[=x^{\frac{i^2}{2}}\sum_{j=0}^{n-1}A_jx^{\frac{j^2}{2}}x^{\frac{-(i-j)^2}{2}} \]

于是,我们设 \(C_i=x^{\frac{i^2}{2}}\sum\limits_{j=0}^{i}A_jx^{\frac{j^2}{2}}x^{\frac{-(i-j-n)^2}{2}}\),此时,由于 \(\forall x\ge n,A_x=0\),所以 \(B_i=C_{i+n}\),而 \(C_i\) 就是一个卷积形式的式子了,我们就可以 \(O(n\log n)\) 求对于任意的 \(n\) 的 DFT 和 IDFT 了。


多项式求逆,即给定 \(n-1\) 次多项式 \(F(x)\),求次数不超过 \(n-1\) 的多项式 \(G(x)\) 满足:

\[F(x)\,G(x)\equiv1(\bmod\ x^n) \]

如何求这个东西呢?我们考虑用倍增来求。
假设我们当前已经知道 \(G_n(x)\) 使得 \(F(x)\,G_n(x)\equiv1(\bmod\ x^n)\),要求 \(G_{2n}(x)\) 使得 \(F(x)\,G_{2n}(x)\equiv1(\bmod\ x^{2n})\)
则:

\[(F(x)G_n(x)-1)^2\equiv0(\bmod\ x^{2n}) \]

\[F^2(x)G^2_n(x)+1-2F(x)G_n(x)\equiv0\pmod{x^{2n}} \]

\[2F(x)G_n(x)-F^2(x)G^2_n(x)-F(x)G_{2n}(x)\equiv0\pmod{x^{2n}} \]

\[G_{2n}(x)\equiv2G_n(x)-F(x)G_n^2(x)\pmod{x^{2n}} \]

于是我们就可以倍增了,复杂度 \(O(n\log n)\)


多项式除法,即给定 \(n\) 次多项式 \(F(x)\)\(m\) 次多项式 \(G(x)\),求一个 \(n-m\) 次多项式 \(H(x)\) 和一个次数小于 \(m\) 的多项式 \(R(x)\),使得:

\[F(x)=G(x)\,H(x)+R(x) \]

如何求呢?我们考虑设 \(F'(x)=F(\dfrac{1}{x})x^n\),即 \(F(x)\)\(0-n\) 次项系数翻转,则(假设 \(R(x)\) 次数为 \(m-1\),不够则补 \(0\)):

\[F'(x)=G'(x)\,H'(x)+x^{n-m+1}R'(x) \]

\[F'(x)=G'(x)\,H'(x)\pmod{x^{n-m+1}} \]

\(H'(x)\) 的次数为 \(n-m\),所以我们在 \(\bmod\ x^{n-m+1}\) 意义下求出的 \(H'(x)\) 和真实的 \(H'(x)\) 相同。
于是通过多项式求逆求出 \(H'(x)\),代回原式解出 \(R(x)\)
复杂度 \(O(n\log n)\)


多项式 ln,即给定多项式 \(F(x)\),求 \(\ln F(x)\pmod{x^n}\)
首先解释下为什么一个多项式可以 \(\ln\)。从这里开始由于我们把多项式看成形式多项式,因此在把 \(f(x)=\ln x\)\(x_0=1\) 处泰勒展开后得到的式子恰为一个关于 \(x\) 的幂级数,把 \(x\)\(F(x)\) 来代入就可以理解为 \(\ln F(x)\)
接下来考虑怎么计算。
\(G(x)=\ln F(x)\pmod{x^n}\),则:

\[G'(x)=\dfrac{F'(x)}{F(x)}\pmod{x^n} \]

于是求个逆求个导卷起来再积分回去即可。
常数项肯定为 \(0\)。(因为 \(F(x)\) 的常数项肯定为 \(1\)


牛顿迭代。即对于一个函数(自变量任意)\(G(x)\),求多项式 \(F(x)\) 使得 \(G(F(x))\equiv0\pmod{x^n}\)
考虑倍增。假设我们知道 \(G(F_n(x))\equiv0\pmod{x^n}\),欲求 \(F_{2n}(x)\) 满足 \(G(F_{2n}(x))\equiv0\pmod{x^{2n}}\)
\(G(x)\)\(G(F_n(x))\) 处作泰勒展开,得到:

\[G(x)=G(F_n(x))+G'(F_n(x))(x-F_n(x))^1/1!+G''(F_n(x))(x-F_n(x))^2/2!+... \]

代入 \(x=F_{2n}(x)\),则

\[G(F_{2n}(x))=G(F_n(x))+G'(F_n(x))(F_{2n}(x)-F_n(x))^1/1!+G''(F_n(x))(F_{2n}(x)-F_n(x))^2/2!+... \]

注意到 \(F_{2n}(x)\)\(F_n(x)\) 的前 \(n-1\) 项应该相同,则 \(F_{2n}(x)-F_n(x)\equiv0\pmod{x^n}\),于是上式在 \(\pmod{x^{2n}}\) 意义下为:

\[0\equiv G(F_n(x))+G'(F_n(x))(F_{2n}(x)-F_n(x))\pmod{x^{2n}} \]

\[F_{2n}(x)\equiv F_n(x)-\dfrac{G(F_n(x))}{G'(F_n(x))}\pmod{x^{2n}} \]

这样就可以倍增了。之前的一些科技也可以用这种牛顿迭代的形式来求(如求逆)。


多项式 exp,即给定 \(P(x)\),求 \(e^{P(x)}\pmod{x^n}\)
如何理解?\(f(x)=e^x\) 同样可以泰勒展开成幂级数。
设函数 \(G(x)=\ln x-P(x)\),利用刚才的牛顿迭代,得到:

\[F_{2n}(x)\equiv F_n(x)(1-\ln F_n(x)+P(x)) \]

写完 \(\ln\) 后倍增即可,复杂度 \(O(n\log n)\),注意常数项为 \(1\)


多项式快速幂,即给定 \(F(x)\),求 \(G(x)\equiv F^k(x)\pmod{x^n}\)
首先可以和普通快速幂一样做,复杂度 \(O(n\log^2n)\)
考虑低一点的复杂度,我们先把 \(F^(x)\)\(\ln\),给系数都乘上 \(k\) 之后再 \(\exp\) 回去。
但有一点问题,就是 \(\ln\)\(\exp\) 均对常数项有要求。如何解决?提公因式即可,注意 \(k\) 的细节。
复杂度 \(O(n\log n)\)

生成函数

一般来说,对于数列 \(\{a_i\}\),我们有两种生成函数:

  1. OGF,一般生成函数,形如 \(F(x)=\sum\limits_{i\ge0}a_ix^i\)
  2. EGF,指数生成函数,形如 \(F(x)=\sum\limits_{i\ge0}\dfrac{a_i}{i!}x^i\)

先看一般生成函数,我们把一个数列写成这样的形式,就可以实现这样的效果:

小例题:给定 \(4\) 种物品,每种物品都有无限个,其中,第一种物品只能选偶数个,第二种只能选 \(5\) 的倍数个,第三种物品最多选 \(4\) 个,第四种物品,最多选 \(1\) 个,求从中选出 \(n\) 个物品的方案数。

考虑写出四种物品的拿取方案序列:
\(\{1,0,1,0,...\},\{1,0,0,0,0,1,0,0,0,0,1,...\},\{1,1,1,1,1,0,0...\},\{1,1,0,0,...\}\)
即序列第 \(i\) 项(从 \(0\) 开始)表示对于该种物品拿 \(i\) 个的方案数。
求出它们的生成函数,把它们乘在一起:

\[\dfrac{1}{1-x^2}\dfrac{1}{1-x^5}\dfrac{x^5-1}{x-1}\dfrac{x^2-1}{x-1} \]

\[=\dfrac{1}{(1-x)^2} \]

\[=(1+x+x^2+x^3+...)^2 \]

此时,所得多项式第 \(n\) 项的系数即为,答案,不难得到答案为 \(n+1\)

这就是一般生成函数的妙用,两个生成函数的卷积可以理解为在做背包合并问题,方便计数。
同时,假设我们要求一个数列的若干项,可以先写出这个数列的生成函数,然后通过某些计算算出这个生成函数的各项系数(比如利用多项式科技),这样一来就解决了问题。

再看指数生成函数,为什么写成这样呢?考虑两个指数生成函数 \(F(x),G(x)\) 乘积:

\[H(x)=(\sum_{i\ge0}\dfrac{a_i}{i!}x^i)(\sum_{j\ge0}\dfrac{b_j}{j!}x^j) \]

\[=\sum_{i\ge0}(\sum_{j=0}^ia_jb_{i-j}C_i^j)\dfrac{x^i}{i!} \]

这样一来,乘在一起后系数不是 \(a_jb_{i-j}\),而是还有一个组合数 \(C_i^j\),就可以解决一些排列组合相关的问题。

Part 3 应用篇

接下来是一些上文的应用。
实际上在 OI 中的应用还是以生成函数的形式为主,但也有利用卷积定义之类的题型。

Pro A 第二类斯特林数 (Luogu 5395)

给定 \(n,m\),求 \(S(n,0),S(n,1),S(n,2),...,S(n,m)\) 的值。
\(tips:1\le m\le n\le 10^5\)

直接暴力算肯定不行,考虑如何优化。
我们发现,把斯特林数写成通项形式:

\[S(n,m)=\dfrac{\sum_{i=0}^m(-1)^iC_m^i(m-i)^n}{m!} \]

\[=\sum_{i=0}^m(-1)^i\dfrac{1}{i!}\dfrac{1}{(m-i)!}(m-i)^n \]

\[=\sum_{i=0}^m\dfrac{(-1)^i}{i!}\dfrac{(m-i)^n}{(m-i)!} \]

于是,构造 \(f(x)=\sum\limits_{i=0}^m\dfrac{(-1)^i}{i!}x^i,g(x)=\sum\limits_{i=0}^m\dfrac{i^n}{i!}x^i\),则 \(S(n,m)=[x^m](f*g)\)
这就是一个经典的应用卷积定义的算法,复杂度 \(O(n\log n)\)

Pro B 付公主的背包(Luogu 4389)

给定 \(n\) 个物品,每种物品的都有无数个,物品 \(i\) 的体积为 \(v_i\)
求挑出若干个物品使得体积和为 \(V\) 的方案数。
\(tips:1\le n,V\le 10^5\)

整个问题就是一个背包问题,考虑用一般生成函数来求方案数。
则第 \(i\) 个物品的生成函数 \(f_i(x)=\sum\limits_{j\ge0}x^{v_ij}=\dfrac{1}{1-x^{v_i}}\)
于是我们要求答案数列的生成函数

\[G(x)=\prod_{i=1}^nf_i(x)=\prod_{i=1}^n\dfrac{1}{1-x^{v_i}} \]

\[\ln G(x)=\sum_{i=1}^n\ln\dfrac{1}{1-x^{v_i}} \]

\[=-\sum_{i=1}^n\ln(1-x^{v_i}) \]

\[(\ln G(x))'=-\sum_{i=1}^n\dfrac{-v_ix^{v_i-1}}{1-x^{v_i}} \]

\[=\sum_{i=1}^nv_ix^{v_i-1}\sum_{j\ge0}x^{v_ij} \]

\[=\sum_{i=1}^n\sum_{j\ge1}v_ix^{v_ij-1} \]

再积回去,得到:

\[\ln G(x)=\sum_{i=1}^n\sum_{j\ge1}\dfrac{x^{v_ij}}{j} \]

于是求出 \(\ln G(x)\),再多项式 \(\exp\) 即可。
复杂度 \(O(V\log V)\),注意在求 \(\ln G(x)\) 时需要用到一些小技巧。

Pro C 排列数 (Luogu 5824)

给定 \(n,m\),求 \(p_{n,m}\) 的值。
\(tips:1\le n,m\le2\times10^5\),其中 \(p_{x,y}\) 表示将 \(x\) 写成 \(y\) 个自然数的和的方案数,不考虑顺序。
例如,\(5=(0+0+5)=(0+1+4)=(0+2+3)=(1+1+3)=(1+2+2)\),因此 \(p_{5,3} = 5\)

首先,我们有一个 \(O(nm)\) 的递推:

\[p_{i,j}=p_{i,j-1}+p_{i-j,j} \]

考虑为什么,我们对于 \(p_{i,j}\),分别考虑 \(j\) 个自然数中是否存在 \(0\) 来转移。
但这道题仅仅这样是不行的,考虑优化。
我们设 \(F_i(x)=\sum_{j\ge0}p_{j,i}x^j\),则:

\[F_i(x)=\sum_{j\ge0}(p_{j,i-1}+p_{j-i,i})x^j \]

\[=F_{i-1}(x)+x^iF_i(x) \]

于是移项得到:

\[F_i(x)=\dfrac{F_{i-1}(x)}{1-x^i} \]

\(dp_{i,0}=[i=0]\),于是 \(F_0(x)=1\),所以:

\[F_i(x)=\prod_{j=1}^i\dfrac{1}{1-x^j} \]

发现了什么?这玩意跟上一题的式子几乎一模一样。
于是直接一样的处理就行了,复杂度 \(O(n\log n)\)

这道题属于一类经典问题,通过构造答案数列的生成函数,利用递推式等关系来得到生成函数的关系并解方程,最后就可以得到答案了。

Pro D 数学竞赛 (Luogu 5517)

给定一个长度为 \(2^{64}\) 的数列 \(\{a_n\}\),其中 \(a_0=-3,a_1=-6,a_2=-12,a_n=3a_{n-1}+a_{n-2}-3a_{n-3}+3^n\)
\(T\) 组询问,每次给定 \(n\),求 \(a_n\pmod{p=10^9+7}\)
\(tips:1\le T\le5\times10^7,0\le n\le2^{64}-1\)

介绍一种比较生成函数的做法:
考虑利用刚才的想法,设 \(F(x)=\sum_{i\ge0}a_ix^i\),则:

\[F(x)=\sum_{i\ge0}(3a_{i-1}+a_{i-2}-3a_{i-3}+3^i)x^i \]

解方程得到:

\[F(x)=\dfrac{12x-3}{(1-3x)^2(1+x)(1-x)} \]

此时,对于这种分母为乘积的形式,一种比较通用的方法是待定系数法,即:

\[F(x)=\dfrac{A}{(1-3x)^2}+\dfrac{B}{1+x}+\dfrac{C}{1-x}+\dfrac{D}{1-3x} \]

此时,\(A,B,C,D\) 可以解出来(参见原题解),然后就把它展开成幂级数形式,最后就得到答案了。
复杂度可以做到 \(O(\sqrt p-T)\)

Pro E 贝尔数 (Luogu 5748)

定义贝尔数 \(B_i=\sum\limits_{j=0}^iS(i,j)\)\(T\) 组询问,求 \(B_n\)
\(tips:1\le T\le1000,1\le n\le10^5\)

考虑贝尔数 \(B_n\) 的组合意义,等于是把 \(n\) 个带放入 \(n\) 个无标号的可空集合中的方案数。
既然要利用上面的想法,我们就应该尝试去找贝尔数的递推公式,发现:

\[B_n=\sum_{j=0}^{n-1}\binom{n-1}{j}B_{n-j-1} \]

即枚举和 \(n\) 在一个集合的是哪些数。

\[B_{n+1}=\sum_{j=0}^n\binom{n}{j}B_{n-j} \]

发现相当于是做卷积的过程中增加了一项系数 \(\binom{n}{j}\),这启示我们使用指数生成函数。
\(F(x)=\sum\limits_{j\ge0}\dfrac{B_j}{j!}x^j,F'(x)=\sum\limits_{j\ge0}\dfrac{B_{j+1}}{j!}x^j\),于是 \(F'(x)=F(x)e^x\)
两边求导移项后得到:

\[B(x)=e^{e^x+c} \]

代入 \(B(0)=1\) 得到 \(c=-1\),于是 \(B(x)=e^{e^x-1}\)
复杂度 \(O(n\log n-T)\)

Part 4 小结

生成函数和多项式作为近些年新兴的出题方向,都透露了极强的数学性,要求 oier 有较高的数学计算能力和思维力,同时又可以方便地结合类似递推之类的内容,因此有很有必要好好掌握。
通过这样的小结形式,积累下来的 trick 或许会有大用吧。

posted @ 2021-01-03 17:12  Tuifei_oier  阅读(172)  评论(0编辑  收藏  举报