生成函数

Posted morning-glory

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了生成函数相关的知识,希望对你有一定的参考价值。

也许更好的阅读体验

一般生成函数(OGF)

引入

考虑一类组合对象组成的集合\\(A\\),其中:

  • 每个元素\\(a\\in A\\)都被定义了“大小”\\(|a|\\),它是一个非负整数。
  • 对于给定的\\(n\\),大小为\\(n\\)的元素的数量是有限的,记作\\(A_n\\)

eg. \\(A\\)是全体\\(01\\)串组成的集合,一个\\(01\\)串的大小被定义为它的长度则\\(A_n=2^n\\)

定义

\\(A\\left( x\\right) =\\sum ^\\infty _i=0A_ix^i\\)
\\(A\\)的一般生成函数
注意

  • \\(A(x)\\)为一个多项式
  • 这里的\\(A_i\\)为第\\(i\\)项的 系数

这是一个形式幂级数,不用考虑何时收敛
这里的\\(x^i\\)为形式幂,无实义,一般也不会去求
但是\\(x^i\\)有区分实际意义的作用,即\\(x^i\\rightarrow\\)\\(i\\)
\\(x^i\\)的系数为第\\(i\\)种状态的答案
这个不好说,举个例子
eg.
\\(A\\)是全体\\(01\\)串组成的集合,则
\\(\\beginalignedA\\left( x\\right) =\\sum ^\\infty _i=02^ix^i\\endaligned=\\dfrac11-2x\\)
最后一步是用的等比数列求和公式,不用考虑何时收敛,所以认为其很大是趋近于0
其中\\(A_i=2^i\\),表示长度为\\(i\\)的答案为\\(2^i\\)
\\(x^i\\)的系数就是长度为\\(i\\)的答案,它是用于区分这个的

运算

有两类组合对象\\(A\\)\\(B\\)

  • 定义\\(C\\)\\(A\\)\\(B\\)的并集
    \\(C(x) =A(x) +B(x),O(n)\\)计算
  • 定义\\(D\\)\\(A\\)\\(B\\)的笛卡尔积,也即\\(D\\)中每个元素\\(d\\)都是\\(A\\)中某元素\\(a\\)\\(B\\)中某元素\\(b\\)拼成的二元组\\((a,b)\\),其大小\\(|d|\\) 定义为\\(|a|+|b|\\)
    \\(D(x) =A(x)B(x)\\)\\(FFT\\)乘法\\(O(nlogn)\\)计算

eg:
\\(A\\)是全体\\(01\\)串组成的集合,\\(B\\)是全体字母组成的集合

\\(\\beginalignedA\\left( x\\right) =\\sum ^\\infty _i=02^ix^i\\endaligned=\\dfrac11-2x\\)
\\(\\beginalignedB\\left( x\\right) =\\sum ^\\infty _i=026^ix^i\\endaligned=\\dfrac11-26x\\)

\\(C(x)=A(x)+B(x)\\)\\(C(x)\\)表示全体\\(01\\)串与全体字母的并集
\\(C(x)\\)\\(x^i\\)项的系数表示长度为\\(i\\)\\(01\\)串与字符串有多少

\\(D(x)=A(x)B(x)\\)\\(D(x)\\)表示\\(01\\)串与字符串拼接出的串(前面是\\(01\\)串,后面是字符串)
\\(D(x)\\)\\(x^i\\)项的系数表示长度为\\(i\\)的拼接出的串有多少
其中某串长度可以为0

个人理解

我们发现上面的例题中的\\(D\\)如果我们不考虑多项式
自己暴力的去算,也有这样的公式
\\(\\beginaligned\\sum_i+j=na_ib_j\\endaligned\\)
其中\\(a_i\\)表示长度为\\(i\\)\\(01\\)串有多少种,\\(b_j\\)表示长度为\\(j\\)的字符串有多少种
然后我们可以发现长度\\(i+j\\)的答案会由\\(i\\)\\(j\\)项得到,再发现其与指数乘法有相似之处,即\\(x^ix^j=x^i+j\\),之后就想到将答案存为其系数,\\(x^i\\)表示实际意义,于是就可以用多项式来解决问题,因为多项式可以\\(FFT\\)优化,比暴力快很多
(我觉得生成函数可能就是这么来的.....)


指数生成函数(EGF)

引入

有时我们需要考虑带标号的组合对象,比如图
\\(n\\)个点的标号图,顶点的标号恰好为\\(1\\sim n\\)

带标号对象的拼接

将两个对象\\(a;b\\)拼接起来,\\(|a|=n,|b|=m\\)

  • 无标号时,只有一种方法
  • 带标号时,规定拼接时拼接对象内部相对标号顺序不变,而互相的标号
    可以改变,则有\\(C_n+m^n(\\beginpmatrix n+m \\\\ n \\endpmatrix)\\)种拼接方法
    因为只要考虑前\\(a\\)中的\\(n\\)个用了哪些标号,剩下的\\(m\\)个给\\(b\\)中的\\(m\\)个,答案唯一,而对象内部相对标号顺序不变,所以得到的标号如何分配也是唯一的
    eg.
    \\(213,21\\)(每个数字是一个标号)拼接,有\\(10\\)种方法
    数字表示分配的标号
    \\(435,21|\\ 425,31|\\ 325,41|\\ 324,51|\\ 415,32\\)
    \\(315,42|\\ 314,52|\\ 215,43|\\ 214,53|\\ 213,54\\)
    如第一种方案\\(435\\)对应的\\(231\\)相对标号顺序不变,\\(31\\)对应的\\(21\\)相对标号顺序也不变

定义

对于带标号组合对象组成的集合\\(A\\),定义
\\(\\beginalignedA\\left( x\\right) =\\sum _i= 0^nA_i\\dfrac x^ii!\\endaligned\\)
\\(A\\)的指数生成函数

运算

有两类组合对象\\(A\\)\\(B\\)

  • 定义\\(C\\)\\(A\\)\\(B\\)的并集
    \\(C(x) =A(x) +B(x),O(n)\\)计算
  • 定义\\(D\\)\\(A\\)\\(B\\)的笛卡尔积,也即\\(D\\)中每个元素\\(d\\)都是\\(A\\)中某元素\\(a\\)\\(B\\)中某元素\\(b\\)拼成的二元组\\((a,b)\\),其大小\\(|d|\\) 定义为\\(|a|+|b|\\)
    \\(D(x) =A(x)B(x)\\)\\(FFT\\)乘法\\(O(nlogn)\\)计算

没错,就是复制上面的内容
对于\\(D(x)\\)
\\(\\beginalignedD(x)=\\sum _i+j=nA_iB_j\\dfrac \\left( i+j\\right) !i!j!\\endaligned\\)
\\(\\beginaligned\\dfrac D(x)n!=\\sum _i+j=n\\dfrac Aii!\\dfrac B_jj!\\endaligned\\)
所以乘法运算成立

个人理解

如引入中的问题
用一般生成函数来求解
\\(\\beginalignedD\\left( x\\right) =A\\left( x\\right) B\\left( x\\right) =\\sum ^n_i+j=nA_i\\cdot B_j\\beginpmatrix n \\\\ i \\endpmatrix\\endaligned\\)
最后又化简成

\\(\\beginaligned\\dfrac D(x)n!=\\sum _i+j=n\\dfrac Aii!\\dfrac B_jj!\\endaligned\\)
于是我们就弄出一个指数生成函数方便运算且省去求组合数

以下\\(A\\)为生成函数

生成序列(seq)

如字面意思,要生成一个序列
序列的顺序是确定的
\\(\\beginalignedseq\\left( A\\right) =\\sum ^\\infty _i=0Ai=\\dfrac 11-A\\endaligned\\)

生成集合(set)

如字面意思,要生成一个集合
集合的顺序是无关紧要的,所以要除以全排列

\\(\\beginalignedset\\left( A\\right) =\\sum ^\\infty _i=0\\dfracA^ii!=e^A\\endaligned\\)

最后一步是因为该式子符合\\(e^x\\)的泰勒展开
关于泰勒展开可看我的该篇博客泰勒公式于牛顿迭代

如有哪里讲得不是很明白或是有错误,欢迎指正
如您喜欢的话不妨点个赞收藏一下吧

以上是关于生成函数的主要内容,如果未能解决你的问题,请参考以下文章

13 生成器函数

生成函数与指数型生成函数

生成器 生成器函数

生成器 三元表达式 列表生成式 匿名函数 内置函数

生成器和生成器函数以及各种推导式

函数——生成器,面向过程编程,三元表达式,生成式,内置函数