生成函数的笔记

众所周知不会生成函数什么计数题都做不了。

几乎对着这篇学的,感谢苹果蓝老师给我的帮助!

只学了我觉得有必要学且我学得会的内容。

前置

多项式

暂时知道一些东西就行。

可以 \(O(n\log n)\) 卷积。

一部分柿子可以分治加卷积,\(O(n\log^2 n)\)。譬如分式求和。

泰勒展开

\[f(x)=\sum_{k=0}^{\infty}\frac{f^{(k)}(0)}{k!}x^k \]

其实容易理解。假设 \(f(x)\) 是无穷项的幂函数的和,那 \(f(0)\) 就是常数项,\(\frac{f^{(k)}(0)}{k!}\) 就是 \(k\) 次项,那个 \(k!\) 是因为导会把指数导下来。

\[\begin{aligned} f(x)&=\ln \frac{1}{1-x} \\ f(x)&=\sum_{k=0}^{\infty}\frac{f^{(k)}(0)}{k!}x^k \\ f^{(k)}(x)&=(1-x)^{-k}(k-1)! \\ f(x)&=\sum_{k=1}^{\infty}\frac{x^k}{k} \end{aligned} \]

广义二项式

\[\begin{aligned} \binom{n}{k}&=\frac{n^{\underline{k}}}{k!} \end{aligned} \]

OGF

生成函数的本质,就是把一个无穷序列映射到环上。

考虑最基础的:

\[\begin{aligned} A(x)&=\sum_{i=0}^{\infty} a_ix^i \end{aligned} \]

高阶前缀和

考虑

\[\begin{aligned} b_n&=\sum_{i=0}^{n}a_i=\sum_{i=0}^{n}a_i\times 1 \\ B&=A\times I \end{aligned} \]

这里 \(I\) 是常函数,我们同时表示常函数的生成函数:\(I=\frac{1}{1-x}\)

差分是逆运算,自然就是 \(I^{-1}\)。这里就不用 \(\mu\) 了,那个是莫反特有的。

自然有 \(k\) 阶的:

\[\begin{aligned} I^k&=(1-x)^{-k} \\ &=\sum_{i=0}^{\infty}\binom{-k}{i}(-x)^i \\ &=\sum_{i=0}^{\infty}\frac{(-k)^{\underline{i}}}{i!}(-x)^i \\ &=\sum_{i=0}^{\infty}\frac{(k+i-1)^{\underline{i}}}{i!}x^i \\ &=\sum_{i=0}^{\infty}\binom{k+i-1}{i}x^i \end{aligned} \]

基本操作

平移

这边移动方向看作二进制哈。

左移显然就是乘 \(x\),左移 \(k\) 位就是乘 \(x^k\)

右移就是乘 \(x^{-k}\),但是要去掉前面几项。

指数下放算子:\(\vartheta A(x)=xA'(x)=\sum_{i}ia_ix^i\)

伸缩

\[A(x^k)=\sum_{i=0}^{\infty} a_ix^{ki} \]

单位根反演

\[\begin{aligned} &\sum_{i=0}^{\infty} a_ix^i[k|i] \\ =&\sum_{i=0}^{\infty} a_ix^i\frac{1}{k}\sum_{j=0}^{k-1}w_k^{ij} \\ =&\frac{1}{k}\sum_{j=0}^{k-1}\sum_{i=0}^{\infty} a_i(w_k^{j}x)^i \\ =&\frac{1}{k}\sum_{j=0}^{k-1}A(w_k^{j}x) \end{aligned} \]

序列通项

以斐波那契生成函数 \(F(x)=\frac{x}{1-x-x^2}\) 为例。

考虑分解成几个生成函数的解。

注意到 \(\begin{aligned}\sum_{i=0}^{\infty}n^ix^i=\frac{1}{1-nx}\end{aligned}\)

将分母分解成两个这种形式的积,有 \(m=\phi,n=\hat{\phi}\)

裂项:\(\begin{aligned}\frac{c}{ab}=\frac{a-b}{ab}\frac{c}{a-b}=(\frac{1}{b}-\frac{1}{a})\frac{c}{a-b}\end{aligned}\)

后面就不多说了。

特征方程法:

\[\begin{aligned} f_n&=\sum_{i=1}^k a_i f_{n-i} \\ x^k&=\sum_{i=1}^k a_i x^{k-i} \\ f_n&=\sum_{i=1}^k \lambda_i x_i ^n \\ &如果出现相同根替换为 \\ &(\sum_{i=1}^{p}\lambda_i n^{i-1})x^n \end{aligned} \]

所有 \(\lambda\) 都是待定系数。

数列 \(k\) 次幂和

\[\begin{aligned} A(x)=&\sum_{k=0}^{\infty}x^k\sum_{i=1}^n a_i^k \\ =&\sum_{i=1}^n\sum_{k=0}^{\infty} a_i^kx^k \\ =&\sum_{i=1}^n\frac{1}{1-a_ix} \end{aligned} \]

分式形式可以分治卷积。

类似的,如果你要求 \(n\) 个数可重地选 \(k\) 个乘积的和:

\[\begin{aligned} Ans_k=[x^k]\prod_{i=1}^n\sum_{j=0}^{\infty}a_i^jx^j=[x^k]\prod_{i=1}^n\frac{1}{1-a_ix} \end{aligned} \]

不可重地:

\[\begin{aligned} Ans_k=[x^k]\prod_{i=1}^n(1+a_ix) \end{aligned} \]

背包问题

完全背包方案计数。即 \(n\) 件物品,第 \(i\) 件体积 \(V_i\)

轻松有 \(Ans_k=[x^k]\prod_{i=1}^n\frac{1}{1-x^{V_i}}\)

乘转加和取 \(\ln\)。这种东西的 \(\ln\) 的泰勒展开我们已经熟能生巧了。

容易注意到系数加的位置是调和级数的。

当然也可以直接分治卷积。总之最后 \(exp\) 回来即可。

异或和问题

小技巧:多设一维形式幂级数 \(y\),再考虑消除,譬如单位根反演。

和之积

\[\begin{aligned} &\prod_{i=1}^{n}(a+b_i) \\ =&[x^n](\sum_{i=0}^{\infty}a^ix^i)(\prod_{i=1}^n1+b_ix) \\ =&[x^n]\frac{1}{1-ax}(\prod_{i=1}^n1+b_ix) \end{aligned} \]

树划分

积之和

定义一个树划分的权值是连通块大小之积,求和。

有朴素方程:

\[f_{u,i}\leftarrow f_{u,i}\sum_{j=0}^njf_{v,j}+\sum_{j=0}^if_{u,j}f_{v,i-j} \]

初值 \(f_{u,1}=1\)

写成生成函数:

\[F_u(x)\leftarrow F_u(x)F_v'(1)+F_u(x)F_v(x) \]

转移需要导数,同时维护一下。

\[F_u'(x)\leftarrow F_u'(x)F_v'(1)+F_u'(x)F_v(x)+F_u(x)F_v'(x) \]

注意到终值是 \(F_1'(1)\),所以带 \(x=1\)

\[\begin{aligned} F_u(1)&\leftarrow F_u(1)F_v'(1)+F_u(1)F_v(1) \\ F_u'(1)&\leftarrow F_u'(1)F_v'(1)+F_u'(1)F_v(1)+F_u(1)F_v'(1) \end{aligned} \]

小巧思做到 \(O(n)\)

莱布尼兹公式:

\[\begin{aligned} (F(x)G(x))^{(k)}=\sum_{i=0}^k\binom{k}{i}F^{(i)}(x)G^{(k-i)}(x) \end{aligned} \]

多元

权值定义为两种权分别求和的积的积,然后求和。

好像要偏导……

其实差不多吧,就是两边一起导。

具体的东西学变分了再说。

常见技巧

快速多项式复合

给出 \(n\) 次多项式 \(F(x)\)\(G(x)\),求 \((F\circ G)(x)\)

幂函数

就是伸缩,直接手改。

一次函数

二项式定理拆开后可以发现大概是系数做一个差卷积。

二次函数

直接配方法,然后按顺序复合即可,与前面一致。

更高次幂多项式

太难了我只能说,好像 noshi91 做到了 \(O(nlog^2 n)\)。别学了。

特殊的分式

通用技巧是想办法拆成只含一个 \(x\) 项的柿子,然后从内导外复合。

复合分式就直接广义二项式拆开做差卷积。

指数函数(\(ae^x\))

\(e\) 展开了,再随手写成个生成函数随便做。咋展开后面 EGF 说。

线性算法与转置原理

线性算法就是由线性函数(可以看作将乘在向量上的矩阵)组成的算法。

那把它翻转我们显然有一个线性算法的转置算法。

众所周知每个矩阵都可以拆成初等矩阵:对换、翻倍、倍加。

那转置算法刚好就是倒过来且每个都转置。

额其中只有倍加对象交换,另外两个其实没有变。

用处似乎是求后缀转求前缀之类的,没遇到就先不说了。

q-模拟

好像就是啥柿子都带个 \(q\)

\[\begin{aligned} \left [ n\right ]_q=\frac{1-q^n}{1-q} = \sum_{i=0}^{n-1}q^i \end{aligned} \]

\(q=1\) 时就是原数。

用 q-整数定义 q-阶乘和 q-组合数。

容易发现这个 q-模拟的东西都可以 \(O(n)\) 预处理。

\[\begin{aligned} A(x)&=\prod_{i=0}^{n} \frac{1}{1-q^ix} \\ A(qx)&=\prod_{i=1}^{n+1} \frac{1}{1-q^ix} \\ &=\frac{1-x}{1-q^{n+1}x}A(x) \\ (1-q^{n+1}x)A(qx)&=(1-x)A(x) \\ a_i(q^i-1)&=a_{i-1}(q^{n+i}-1) \end{aligned} \]

推的方式是把生成函数拆开,\(A(qx)\) 系数 \(a_iq^i\)

\[\begin{aligned} a_i(q^i-1)&=a_{i-1}(q^{n+i}-1) \\ a_i\frac{1-q^i}{1-q}&=a_{i-1}\frac{1-q^{n+i}}{1-q} \\ a_i&=a_{i-1}\frac{[n+i]_q}{[i]_q} \end{aligned} \]

总之你把这玩意当正常的用。容易猜出 \(a_i=\binom{n+i}{i}_q\)

其余也是类似的方法,代个 \(qx\) 即可。

类似地,有

\[\begin{aligned} A(x)&=\prod_{i=0}^n(1+q^ix) \\ a_i&=q^{\frac{i(i-1)}{2}}\binom{n+1}{i}_q \end{aligned} \]

在解递推式时一般用于处理常数项带指数时。

其它技术不太需要了吧,记个结论,q-二项式反演。和前面的那个挺像。

\[\begin{aligned} g_{n}&=\sum_{i=0}^n\binom{n}{i}_qf_i \\ f_{n}&=\sum_{i=0}^n (-1)^i q^{\frac{i(i-1)}{2}}\binom{n}{i}_qg_{n-i} \end{aligned} \]

解析组合

用 $\mathcal{A} $ 表示。每个元素定义了大小(譬如无标号有根树的节点个数),且有限。\(\mathcal{A}_k\) 表示大小为 \(k\) 的元素集合。

可以定义生成函数 \(\mathcal{A}=\sum_{i} |\mathcal{A}_i|x^i\),其实就是每种大小的元素个数序列组成的生成函数。

也可以表示成 \(\mathcal{A}=\sum x^{|a|}\)

对元素钦定一些运算。

笛卡尔积:元素的笛卡尔积就是视其为有序对,大小为两者之和。组合类的笛卡尔积可以组成新的组合类。

容易观察到体现在生成函数上就是卷积。

不交并:相同大小加一起。生成函数相加。

SEQ:多个元素生成的序列。

\[\begin{aligned} \text{SEQ}(\mathcal{A})&=\sum_{i=0}^{\infty} \mathcal{A}^i \\ &=\frac{1}{1-\mathcal{A}} \end{aligned} \]

AMP:变成指定长度的组合。\(\text{AMP}_k(\mathcal{A})=A(x^k)\)。懒得在意格式了反正意思是这个意思。

群论与无标号组合构造

置换群上的组合类

\(\mathcal{A}\) 的元素 \(a\) 都可以描述成 \(\mathcal{B}\) 的有序组合(元素组成的有序对)。

有序对大小(注意不是有序对内部元素大小和,是元素数量)为 \(a\) 的容。

\(G_k\) 表示 \(k\) 阶置换群(置换群不一定是包含全部!这不是全变换群!),\(G={G_0,G_1,G_2,...}\) 是置换群列。

\(a\)\(a'\) 等价当且仅当存在 \(g\in G\)\(g(a)=a'\)

可以这么写:显然有 \(a\) 的轨道 \(G_{|a|}(a)\),那么 \(a'\)\(a\) 等价就是 \(a'\in G_{|a|}(a)\)

一个轨道记号:\(\mathcal{A}/G_{\mathcal{B}}=\{G_{|a|}(a)|a\in\mathcal{A}\}\)

其实就是所有等价类的组合类。

构造

CYC:令 \(G\) 是循环同构置换群列。

\[\text{CYC}(\mathcal{A})=(\text{SEQ}(\mathcal{A}-\{\varepsilon\}))/G_{\mathcal{A}} \]

即用 \(\mathcal{A}\) 中元素组成的序列划分为无标号等价类。看作完全背包即可。

考虑计算这个组合类的生成函数。

\[\begin{aligned} \text{CYC}_k(\mathcal{A})&=(\mathcal{A}^k)/G_{\mathcal{A}} \\ \text{CYC}_k(A(x))&=\frac{1}{k}\sum_{i=0}^{k-1}(\text{AMP}_{\frac{k}{\text{gcd}(i,k)}}(A))^{\text{gcd}(i,k)} \\ \text{CYC}_k(A(x))&=\frac{1}{k}\sum_{i=0}^{k-1}A(x^{\frac{k}{\text{gcd}(i,k)}})^{\text{gcd}(i,k)} \\ \text{CYC}_k(A(x))&=\frac{1}{k}\sum_{d|k}\varphi(d)A(x^{d})^{\frac{k}{d}} \end{aligned} \]

用到了欧拉反演。

\[\begin{aligned} \text{CYC}(A(x))&=\sum_{k}\frac{1}{k}\sum_{d|k}\varphi(d)A(x^{d})^{\frac{k}{d}} \\ \text{CYC}(A(x))&=\sum_{d}\varphi(d)\sum_{d|k}\frac{1}{k}A(x^{d})^{\frac{k}{d}} \\ \text{CYC}(A(x))&=\sum_{d}\frac{\varphi(d)}{d}\sum_{k}\frac{1}{k}A(x^{d})^{k} \end{aligned} \]

中间把 \(k\) 换成了 \(kd\)。后面那个柿子用屁股看都知道是 \(\ln\) 的泰勒展开。

\[\begin{aligned} \text{CYC}(A(x))&=\sum_{d}\frac{\varphi(d)}{d}\sum_{k}\frac{1}{k}A(x^{d})^{k} \\ \text{CYC}(A(x))&=\sum_{d}\frac{\varphi(d)}{d}\ln(\frac{1}{1-A(x^d)}) \end{aligned} \]

如果考虑前 \(n\) 项,则复杂度是 \(O(n\log n)\) 的。

Euler/MSET:又称可重集构造。令 \(G\) 是全变换群列。

\[\begin{aligned} \text{Euler}(\mathcal{A})=\text{SEQ}(\mathcal{A})/G_{\mathcal{A}} \end{aligned} \]

简单来说就是无标号拼合,即所谓可重集。

根据组合意义写出的组合类计算式十分的浅显易懂。

搓一下生成函数式:

\[\begin{aligned} B(x)&=\prod_a\sum_k x^{|a|k} \\ &=\prod_a\frac{1}{1-x^{|a|}} \\ &=\prod_{k}(\frac{1}{1-x^k})^{A_k} \end{aligned} \]

看作完全背包可获得同样公式。

计算考虑先 \(\ln\)\(\exp\)

\[\begin{aligned} B(x)&=\prod_{k}(\frac{1}{1-x^k})^{A_k} \\ &=\exp\ln\prod_{k}(\frac{1}{1-x^k})^{A_k} \\ &=\exp \sum_k A_k\sum_{i}\frac{x^{ki}}{i} \\ &=\exp\sum_{i}\frac{A(x^i)}{i} \end{aligned} \]

\(\text{Euler}_k\) 非常难算。总之枚举集合后化柿子,复杂度分拆数。

PSET:幂集构造。

\[\begin{aligned} \text{PSET}(\mathcal{A})&=\prod_{a}(\{\varepsilon\}+\{a\}) \end{aligned} \]

非常简单,选或不选。

中途推导和上面类似就不推了。

\[\begin{aligned} \text{PSET}(A(x))&=\prod(1+x^i)^{a_i} \\ &=\exp \sum_{i\ge 1}(-1)^{i-1}\frac{A(x^i)}{i} \end{aligned} \]

上面两个的逆,都考虑先 \(\ln\),然后从小到大推系数。就是先求答案较小项,再去用已知较小项更新较大项。

应用:无标号树计数

现在我们闭着屁股也能写出无标号有根树的转移了:

\[F(x)=x\text{Euler}(F(x)) \]

由于 \(\exp\) 常数大还难写,这里直接讲分治 FFT 做法。

你求 \(\ln\) 再求导,原函数导数分开看,省略一些步骤就可以分治处理。

练习

更多的练习后面再说吧……

拉格朗日反演

link

自认为写得还行。

EGF

指数生成函数我们敬爱你口牙!

主要解决有序计数问题。

先提前给出定义式:

\[\begin{aligned} \hat{A}(x)=\sum_i\frac{a_i}{i!}x^i \end{aligned} \]

理解

譬如说你考虑多重集组合数。发现把阶乘的逆元直接移到系数里就可以处理所有有序问题了。最后答案乘阶乘即可。

常函数的 EGF:\(\hat{I}=\sum \frac{x^i}{i!}=e^x\)

EGF 卷积的代数意义就是组合数卷积。求导右移积分左移。

exp 的组合意义

终于到了(流泪)!

先思考一个简单的问题:\(n\) 个有标号球丢进 \(k\) 个无标号盒子,大小为 \(i\) 的盒子方案 \(a_i\),求方案。

显然

\[\begin{aligned} S(n,k)=\frac{n!}{k!}[x^n]\hat{F}(x)^k \end{aligned} \]

尝试这样一件事:对所有 \(k\) 一起统计。

然后……

\[\begin{aligned} \frac{S(n)}{n!}=[x^n]\sum_{k=0}^{\infty}\frac{\hat{F}(x)^k}{k!} \end{aligned} \]

你在干啥?

\[\begin{aligned} \hat{S}(n)=e^{\hat{F}(x)} \end{aligned} \]

\(\exp\) 登场!

故 EGF 下 \(\exp\) 的组合意义就是:\(n\) 划分,大小为 \(i\) 的部分带权 \(a_i\) 的积之和

用柿子表示就是:

\[\sum_{\sum c_i = n}\prod a_{c_i} \]

解析组合-有标号 DLC

又来。。。

大同小异,虽然有些不同,主要是为了契合 EGF。

笛卡尔积:序列归并。柿子一样。

SEQ:一坨序列归并。柿子一样。

PNT:无根转有根。指标下移算子。

CYC:组合类运算无区别。柿子有不同:

\[\begin{aligned} \text{CYC}_k(A(x))&=\frac{A(x)^k}{k} \\ \text{CYC}(A(x))&=\ln \frac{1}{1-A(x)} \end{aligned} \]

SET:与 \(\text{Euler}\) 一致。发现就是 exp 的组合意义,可用于任意图连通图转换。

\[\begin{aligned} \text{SET}(A(x))=e^{A(x)} \end{aligned} \]

SUB:子结构替换。

\(A\) 内部的结构替换成 \(B\) 其实就是复合。

ADDDEL:很简单,插入就是积分,删除就是导。

集合幂级数

之前没认真学过,稍微补一下。

注意集合、二进制、\(\mathbb{F}_2\) 的向量本质都是等价的,所以接下来会混着用,不清楚的时候就转换成你喜欢的表述吧。

朴素地说就是把集合记在了指数上,然后就可以定义与、或、异或卷积。

FWT/FMT

FFT/FWT 一类快速卷积的本质就是求值插值。

FFT 求的就是几个单位根,然后插回来。

以或卷积的 FMT 为例,我们求 \(T\in \mathbb{F}_2^{n}\) 的所有向量。


这里的求值需要仔细说明一下,毕竟集合幂级数的求值可没有那么直观。

首先 \(x^S\) 只是形式级数。可以将 \(x^S\) 看作一个 \(S\) 方向的单位向量,我们定义的运算针对两个单位向量的合成。

集合幂级数本身可以看作域,可以构造到另一个权值域的同态。

于是向量 \(T\) 的权值,可以定义为 \(T\) 导出的同态 \(\chi_T\)。事实上就是为每个单位向量赋权的操作。

由于单位向量只和 \(S\) 有关,不妨记 \(T\) 导出的 \(S\) 的权是 \(\chi_T(S)\)

位运算是直积构造的,我们可以拆位:

\[\chi_T(S)=\prod c(t_i,s_i) \]

外层 \(\prod\) 对应你设计的权值的乘法。

对于 \(c\),它需要对 \(s_i\) 满足同态映射,满足这个条件的函数其实基本确定了。

接下来只需要分别对每种运算解方程即可。接下来 \(s,t\) 暂时表示单个位置,简记 \(f(s)=c(t,s)\)

  • 对于 OR 运算。
    • \(t=0\) 时,\(f(0)=1,f(1)=0\)
    • \(t=1\) 时,\(f(0)=1,f(1)=1\)
    • 综上,\(c_{OR}(t,s)=[s\le t]\)
  • 对于 AND 运算。
    • 直接 \(c_{AND}(t,s)=[t\le s]\)
  • 对于 XOR 运算。
    • 这个比较复杂。
    • 解出来是 \((-1)^{ts}\)

然后再把 \(c\) 的值乘起来得到 \(\chi_T\)。那么对于一个 \(T\) 的求值就是对每一位多算 \(\chi_T(S)\) 的值。

对于 OR:

\[\hat{f}_T=\sum_{S\subseteq T} f_{S} \]

对于 AND:

\[\hat{f}_T=\sum_{T\subseteq S} f_{S} \]

对于 XOR:

\[\hat{f}_T=\sum_{S}(-1)^{|S\cdot T|}f_{S} \]

这里的 \(\cdot\) 是点积。


关于快速求得 FMT/FWT 的方法:

对每一位考虑贡献。然后考虑当前位的 \(0\)\(1\) 的贡献。

事实上,刚才的 \(c(t,s)\) 的关系写成一个矩阵。

那只需要推导矩阵左乘的影响即可。逆变换本质是逆矩阵。

复杂度 \(O(n2^n)\)

拓展 k-FWT

从高观点上来看就是 \(\mathbb{F}_k\) 的操作。

原来用 \(-1,0,1\) 表示的函数改用单位根即可。

子集卷积

我们从来没有规定 \(f_S\) 必须是数什么的。

事实上定义 \(f_S\) 是多项式其也构成环,所以也能用。

同样可以用形式幂级数表示多项式。这里区别 \(x\) 我们用 \(z\)

当然如果你愿意 \(z\) 那里再套个集合幂级数也是可以的。


对于子集卷积,我们定义

\[F(z,x)=\sum_{S} (f_sz^{|S|})x^S \]

定义关于集合幂级数的运算是或卷积,那么卷积就是:

\[(f_Az^{|A|}x^A)(g_Bz^{|B|}x^B)=(f_Ag_B)z^{|A|+|B|}x^{A\cup B} \]

那么最后子集卷积就是恰取 \(z^{|S|}\) 的答案。

值得一提的是把 \(z\) 放前面一维而不是当多项式更好写也更快。

exp/ln/inv

关于集合幂级数的三种函数:

EXP:

\[g_S=\sum_{T\subseteq S,k\in T} f_Tg_{S-T} \]

Ln:

\[g_S=f_S-\sum_{T\subseteq S,T\ne S,k\in T}g_Tf_{S-T} \]

Inv:

\[g_S=-\sum_{T\subseteq S,T\ne\varnothing}f_Tg_{S-T} \]

除了 Inv 的组合意义都挺显然的,然后 Inv 可以代数推导。\(k\)\(\text{lowbit}\) 或者任意一位。

这三个形式事实上都是半在线卷积。

小技巧

提取分式系数:BM

posted @ 2025-12-19 16:07  一念行空  阅读(3)  评论(1)    收藏  举报