Loading

学习笔记——生成函数初见

可能不严谨,但是能看懂,并且可以用~

概论

你从小就被 \(\texttt{m}\color{red}{\texttt{yee}}\) 在生物课上教育生成函数,但是那个时候的你,连生成函数是什么都不知道。

后来,你在学考前粗粗地看了看,发现完全没法看懂。

最后,听 \(\texttt{M}\color{red}{\texttt{r_Spade}}\) 讲生成函数,终于初步弄懂了生成函数,并经过一些例题的磨炼稍微能推一下式子,于是就来这里写博客了。

首先我们需要一些前置芝士——多项式及其基本运算。

前置芝士

主要介绍多项式和基本的运算,如果你已经熟练掌握,可跳过此部分。

多项式表示

这个大家都会,用一个 \(f\) 来表示一个多项式,而 \([x^n]f\) 表示多项式 \(f\) 的第 \(n\) 次项的系数。

多项式乘法

你可以考虑一波小学的时候学的分配律,然后合并同类项,就是我们所说的多项式乘法。基于此,我们有一个 \(O(n^2)\) 的乘法:

\[[x^n]h=\sum_{k=0}^n[x^k]f\cdot[x^{n-k}]g \]

我们把这个玩意儿记作:

\[h=f*g \]

然后如果你会 FFT 或者 NTT 等算法,可以把它优化到 \(O(n\log n)\)

顺带一提(下面要用),若干多项式相乘会有如下形式:

\[[x^n](f_{1}*\cdots f_{m})=\sum_{k_1,\cdots,k_m}[\sum_{j=1}^m k_i=n](\prod_{j=1}^m[x^{k_j}]f_j) \]

多项式求逆

有的时候,我们会在模意义下,求两个多项式的乘法,如果多项式 \(f,g\) 满足:

\[f*g\equiv 1\pmod p \]

那么 \(f,g\) 就是互逆的,我们类比于整数的逆元,记作:

\[g=f^{-1} \]

那么我们根据乘法的定义,可以推出求逆的式子:

\[[x^n]f^{-1}=\begin{cases} \qquad\qquad\dfrac{1}{[x^0]f}&,n=0\\ -\dfrac{\sum_{k=0}^{n-1}[x^k]f^{-1}\cdot[x^{n-k}]f}{[x^0]f}&,n>0 \end{cases}\]

多项式复合

也就是喜闻乐见的函数嵌套,我们记作 \(f\circ g\)。一般不会直接计算。

多项式求导

这东西大家都会,有:

\[[x^n]f'=(n+1)[x^{n+1}]f \]

然后一些性质:

\[(f\plusmn g)'=f'\plusmn g' \]

\[(f*g)'=f'*g+f*g' \]

\[(f\circ g)'=f'\circ g*g' \]

根据这些性质,我们可以得到:

\[(\dfrac{f}{g})'=\dfrac{f'*g-f*g'}{g^2} \]

多项式 exp

也称为多项式指数函数。记作:\(e^x\)

其来源于我们希望能得到一个多项式使得其导数是其本身。根据求导的定义,我们有:

\[[x^n]f'=(n+1)[x^{n+1}]f=[x^n]f \]

\[[x^{n+1}]f=\dfrac{[x^n]f}{n+1} \]

此时我们令 \([x^0]f=1\),则有:

\[e^x=\sum_{k\ge 0}\dfrac{x^k}{k!} \]

那么我们定义一个多项式 \(f\) 的指数函数为其和 \(e^x\) 的复合,记作:\(e^f\)。则易得:

\[e^f=\sum_{k\ge 0}\dfrac{f^k}{k!} \]

根据上式,我们注意到 \(f^k\) 的前 \(k\) 项是 \(0\),所以如果我们需要求指数函数的第 \(n\) 项系数,可以这样子:

\[[x^n]e^f=\sum_{k=0}^n[x^n]\dfrac{f^k}{k!} \]

顺带一提,指数函数有着代数相似的良好性质:

\[e^{f+g}=e^f*e^g \]

\[e^{kf}=(e^f)^k \]

为了更快地求指数函数,我们利用导数:令 \(g=e^f\),则有:

\[g'=(e^x\circ f)'=(e^x)'\circ f*f'=e^x\circ f*f'=e^f*f'=g*f' \]

于是我们分别取第 \(n\) 项系数:

\[(n+1)[x^{n+1}]g=\sum_{k=0}^n[x^k]g\cdot[x^{n-k}]f' \]

有了这个式子可以 \(O(n^2)\) 递推,当然也可以优化到 \(O(n\log n)\)

多项式 ln

你可以把这玩意儿看成是代数的对数。即有:

\[e^f=g\Leftrightarrow \ln g=f \]

快乐。

至此,多项式的基本运算,也就是生成函数的基础就介绍完毕。

进入正题

普通生成函数

首先,我们需要明确一件事:生成函数是什么。这里抽象地解释一下就是:对于一个数列 \(a\)多项式 \(f\) 如果满足:

\[a_n=[x^n]f \]

则我们称这个多项式 \(f\) 是数列 \(a\) 的一个普通生成函数(OGF)。是的,生成函数是一个一个一个多项式!

引入

考虑一个小学生题。

你有 \(a\) 件不同的上衣,\(b\) 条不同的裤子,\(c\) 双不同的鞋子。问你有多少种不同的搭配方式?

你是这样算的:上衣有 \(a\) 种选择,裤子是 \(b\) 种,鞋子是 \(c\) 种,那么根据乘法原理应当是 \(a\times b\times c\) 种。

然而,如果我们把每种选择用加法原理展开,应该是这样的:

\[\begin{matrix} (\underbrace{1+1+\cdots+1})\times (\underbrace{1+1+\cdots+1})\times (\underbrace{1+1+\cdots+1})\\a \text{个} 1\qquad\qquad\qquad\,\, b \text{个} 1\qquad\qquad\qquad\,\, c \text{个} 1 \end{matrix} \]

以上只是感受一下。

然后我们继续问:

如果这 \(a\) 件上衣,\(b\) 条裤子和 \(c\) 双鞋子分别都有特定的价格,那请问,总价格是 \(n\) 的方案数是多少?

这个题好像可以 dp?我们可以考虑设 \(dp_{1/2/3,i}\) 表示考虑了衣服/衣服+裤子/衣服+裤子+鞋子之后总价是 \(i\) 的方案数。然后暴力转移就是 \(O(nm)\) 的了,其中 \(m\) 就是 \(a+b+c\)。这个东西已经很难优化了。

但是我们来一波人类智慧,我们利用生成函数,使得其能通过某种代数运算的方式直接完成一整行的转移。我们掏出三个多项式 \(A,B,C\),分别表示衣服裤子和鞋子。然后 \([x^n]A\) 表示衣服中价格为 \(n\) 的数量,以此类推。

然后我们把这三个多项式乘起来,得到 \(f\),那么有:

\[[x^n]f=\sum_{a,b,c}[a+b+c=n][x^a]A\cdot[x^b]B\cdot[x^c]C \]

现在,我们把这个多项式的 \(x\) 的指数看成是上面 \(dp\) 中的 \(i\),那么我们惊奇地发现,这个东西实际上就是 \(dp\) 的转移。然后我们考虑 \(f\) 是啥。我们假设数列 \(b\),其中 \(b_i\) 表示 \(n=i\) 时的答案。不难发现,\(f\) 就是答案数列 \(b\) 的生成函数。

也就是说,我们将这三个多项式乘起来,然后取第 \(n\) 项系数,就是我们需要求的答案。这个东西,用 FFT/NTT 可以优化到 \(O(n\log n)\)

经过上面这个例子,我们不难发现,生成函数实际上是借助于 \(x\) 的指数来区分不同的系数,可以把它当成 \(dp\) 的下标(或者说是状态)。因此,我们不会向生成函数中带入任何 \(x\) 的值,它只作为一个标志。

求 OGF

有了对生成函数的初步了解,来看几道题吧。

有无穷多张 \(1,5,10,20,50,100\) 元的纸币,求凑成 \(n\) 元的方案数。

我们来求它的生成函数。考虑每种纸币选多少,那么对于面值是 \(i\) 的纸币,其构成多项式:

\[f_i=\sum_{k\ge 0} x^{ki}=\dfrac{1}{1-x^i} \]

那么我们将这些多项式全部乘起来,和第一个例子相同,相当于让他们自由组合。最后这个多项式就是答案序列的生成函数,那我们取第 \(n\) 项系数,就是答案了。

设斐波那契数列生成函数 \(f\),且 \([x^0]f=0,[x^1]f=1\),求 \(f\)

不同与之前所遇到的组合题,这题直接要求一个特定数列的生成函数。面对这种问题,通常选择先写出递推式子:\([x^n]f=[x^{n-1}]f+[x^{n-2}]f\)\(n\ge 2\)。然后我们把他全部转化成同一项的系数,即:\([x^n]f=[x^n]fx+[x^n]fx^2\),通过移项化简得到:

\[[x^n](f(1-x-x^2))=0 \]

也就是说多项式 \(f\) 乘上多项式 \(1-x-x^2\) 后第 \(n\) 项(\(n\ge 2\))的系数永远是 \(0\)

然后我们考虑 \(n=1\) 的情况,那么有:

\[[x^1](f(1-x-x^2))=[x^1]f\cdot1+[x^0]f\cdot(-1)=1 \]

以及 \(n=0\) 的情况,那么有:

\[[x^0](f(1-x-x^2))=[x^0]f\cdot1=0 \]

那么也就是说,对于多项式 \(g=f(1-x-x^2)\),只有一次项系数为 \(1\),其余都是 \(0\),那么就容易得到 \(g=x\),那么就有:

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

这便是斐波那契数列的生成函数。

指数生成函数

我先不说这是个啥,我们先来引入。

引入

先来考虑这样一个问题:

给你一张完全图,求生成树的个数。

这个问题直接用矩阵树定理,求行列式之后可以得到应该是 \(n^{n-2}\)

现在我们把这个题升级一下:

\(n\) 个点的无向图,形状恰好是不连通的两棵树的图的数量。

看到这个题可以想到是相当于求两棵不相交的生成树。那么想要把图分成两部分。于是你写出了这样一个暴力求的式子:

\[\sum_{k\ge 0}^n{n\choose k}\times \dfrac{1}{2}\times k^{k-2}\times (n-k)^{n-k-2} \]

这个 \(\dfrac{1}{2}\) 是因为我们需要去除两棵树的顺序。

类似于上面提到的 OGF,我们尝试把这玩意儿变成答案数列的生成函数的系数,即:

\[[x^n]f=\dfrac{1}{2}\sum_{k\ge 0}^n\dfrac{n!}{k!(n-k)!}\times k^{k-2}\times (n-k)^{n-k-2} \]

我们巧妙地分配这个组合数的阶乘,得到:

\[\dfrac{[x^n]f}{n!}=\dfrac{1}{2}\sum_{k\ge 0}^n\dfrac{k^{k-2}}{k!}\times \dfrac{(n-k)^{n-k-2}}{(n-k)!} \]

然后我们非常智慧地定义一个 \(g\) 是第一个问题的生成函数,那么有:

\[[x^n]g=n^{n-2} \]

欸那我们带入上面这个式子不就是:

\[\dfrac{[x^n]f}{n!}=\dfrac{1}{2}\sum_{k\ge 0}^n\dfrac{[x^k]g}{k!}\times \dfrac{[x^{n-k}]g}{(n-k)!} \]

然后我们有一个 \([x^n]F=\dfrac{[x^n]f}{n!},[x^n]G=\dfrac{[x^n]g}{n!}\)。带入得到:

\[F=\dfrac{G^2}{2} \]

很神奇,如果我们知道了 \(G\)(而我们确实容易计算这个多项式),那么通过多项式乘法就能得到 \(F\) 了。复杂度可以是 \(O(n\log n)\)

我们发现上面这个 \(F,G\) 两个多项式和 OGF 不同,它在 OGF 的基础上除了一个阶乘,很像多项式指数函数的形式,所以我们叫它指数生成函数(EGF)

有了 EGF,我们可以继续升级上面这个问题:

EGF 的进一步应用

现在来考虑这样一个问题:

\(n\) 个点的无向图中,形状恰好是不连通的若干棵树的图的数量。

换句话说,我们把前面的 \(2\) 变成了若干。

同样我们先写出这个暴力的式子:

\[[x^n]f=\sum_{k\ge 0}^n\dfrac{1}{k!}\sum_{a_1,\cdots,a_k}[\sum_{i=0}^ka_i=n]{n\choose a_1,\cdots,a_k}(\prod_{i=1}^k[x^{a_i}]g) \]

模仿上面分配这个组合数,得到:

\[F=\dfrac{G^k}{k!} \]

你是否觉得眼熟,啊对,这东西就是指数函数:

\[F=e^G \]

好家伙。。。

总结

我们现在遇到了两种生成函数,也是最常见的两种。这两种生成函数都会用于组合计数类问题中。OGF 擅长对于组合成为特定值的问题,而 EGF 擅长对于树图的计数,其特点是暴力计算式子中含有二项式,然后通过巧妙分配其阶乘可以得到 EGF。

posted @ 2022-07-25 19:00  ZCETHAN  阅读(60)  评论(2编辑  收藏  举报