简单多项式学习笔记
离谱的多项式
——简单多项式和生成函数学习笔记
By Tuifei_oier
Part 1 前言
多项式和生成函数同属 OI 中数学方面的知识,在学习它们的过程中,不仅要掌握一些基础的对于它们本身的知识和操作,更要学会去通过构造和计算来解决相关的问题。
因此,本文先从定义入手记录一些多项式和生成函数的基础操作,再记录一些经典的应用和构造方式。
Part 2 科技篇
随便编的定义
首先,我们给出形式幂级数的定义:
对于形式幂级数 \(F(x)=\sum\limits_{i\ge0}a_ix^i\),我们不关心 \(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\) 项的系数。
多项式全家桶
首先是最基础的卷积,即:
就是把两个多项式相乘,利用 FFT 可以 \(O(n\log n)\) 解决。
一维循环卷积,即:
发现实际上 FFT 求的就是循环卷积,于是直接做之后把系数加到 \(\bmod\ n\) 后的位置上就好了。
对于二维循环卷积,即:
我们可以先求出对于两边的矩阵做 DFT,然后对位相乘得到新矩阵再 IDFT 回去。
如何 DFT 一个矩阵呢?我们可以先把每一行看成一个多项式系数数列,然后把它们代表的多项式都 DFT,对得到的新矩阵的每一列再进行相同操作,最后就得到了原矩阵的 DFT 矩阵,IDFT 就是把整个操作逆向进行即可。
对于高维,同理。
关于循环卷积有一个重要的算法——Bluestein 算法。
因为在 DFT 和 IDFT 过程中都要求 \(n\) 为 \(2\) 的若干次方;而当 \(n\) 不为 \(2\) 的次方时,我们要不一次一次暴力做,但这样可能会导致复杂度问题;或者,我们就可以利用这个算法。具体的说,对于长度为 \(n\) 的数列 \(A\),我们要求长度为 \(n\) 的数列 \(B\) 满足:
于是,我们设 \(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)\) 满足:
如何求这个东西呢?我们考虑用倍增来求。
假设我们当前已经知道 \(G_n(x)\) 使得 \(F(x)\,G_n(x)\equiv1(\bmod\ x^n)\),要求 \(G_{2n}(x)\) 使得 \(F(x)\,G_{2n}(x)\equiv1(\bmod\ x^{2n})\)。
则:
于是我们就可以倍增了,复杂度 \(O(n\log n)\)。
多项式除法,即给定 \(n\) 次多项式 \(F(x)\) 和 \(m\) 次多项式 \(G(x)\),求一个 \(n-m\) 次多项式 \(H(x)\) 和一个次数小于 \(m\) 的多项式 \(R(x)\),使得:
如何求呢?我们考虑设 \(F'(x)=F(\dfrac{1}{x})x^n\),即 \(F(x)\) 的 \(0-n\) 次项系数翻转,则(假设 \(R(x)\) 次数为 \(m-1\),不够则补 \(0\)):
而 \(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}\),则:
于是求个逆求个导卷起来再积分回去即可。
常数项肯定为 \(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))\) 处作泰勒展开,得到:
代入 \(x=F_{2n}(x)\),则
注意到 \(F_{2n}(x)\) 与 \(F_n(x)\) 的前 \(n-1\) 项应该相同,则 \(F_{2n}(x)-F_n(x)\equiv0\pmod{x^n}\),于是上式在 \(\pmod{x^{2n}}\) 意义下为:
这样就可以倍增了。之前的一些科技也可以用这种牛顿迭代的形式来求(如求逆)。
多项式 exp,即给定 \(P(x)\),求 \(e^{P(x)}\pmod{x^n}\)。
如何理解?\(f(x)=e^x\) 同样可以泰勒展开成幂级数。
设函数 \(G(x)=\ln 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\}\),我们有两种生成函数:
- OGF,一般生成函数,形如 \(F(x)=\sum\limits_{i\ge0}a_ix^i\);
- 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\) 个的方案数。
求出它们的生成函数,把它们乘在一起:
此时,所得多项式第 \(n\) 项的系数即为,答案,不难得到答案为 \(n+1\)。
这就是一般生成函数的妙用,两个生成函数的卷积可以理解为在做背包合并问题,方便计数。
同时,假设我们要求一个数列的若干项,可以先写出这个数列的生成函数,然后通过某些计算算出这个生成函数的各项系数(比如利用多项式科技),这样一来就解决了问题。
再看指数生成函数,为什么写成这样呢?考虑两个指数生成函数 \(F(x),G(x)\) 乘积:
这样一来,乘在一起后系数不是 \(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\)。
直接暴力算肯定不行,考虑如何优化。
我们发现,把斯特林数写成通项形式:
于是,构造 \(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}}\)。
于是我们要求答案数列的生成函数
再积回去,得到:
于是求出 \(\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}\),分别考虑 \(j\) 个自然数中是否存在 \(0\) 来转移。
但这道题仅仅这样是不行的,考虑优化。
我们设 \(F_i(x)=\sum_{j\ge0}p_{j,i}x^j\),则:
于是移项得到:
而 \(dp_{i,0}=[i=0]\),于是 \(F_0(x)=1\),所以:
发现了什么?这玩意跟上一题的式子几乎一模一样。
于是直接一样的处理就行了,复杂度 \(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\),则:
解方程得到:
此时,对于这种分母为乘积的形式,一种比较通用的方法是待定系数法,即:
此时,\(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\) 个无标号的可空集合中的方案数。
既然要利用上面的想法,我们就应该尝试去找贝尔数的递推公式,发现:
即枚举和 \(n\) 在一个集合的是哪些数。
发现相当于是做卷积的过程中增加了一项系数 \(\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(0)=1\) 得到 \(c=-1\),于是 \(B(x)=e^{e^x-1}\)。
复杂度 \(O(n\log n-T)\)。
Part 4 小结
生成函数和多项式作为近些年新兴的出题方向,都透露了极强的数学性,要求 oier 有较高的数学计算能力和思维力,同时又可以方便地结合类似递推之类的内容,因此有很有必要好好掌握。
通过这样的小结形式,积累下来的 trick 或许会有大用吧。