zoukankan      html  css  js  c++  java
  • 浅谈生成函数与组合计数,多项式全家桶(未完)

    引言

    ​ 组合计数问题是信息学竞赛中常见的一类问题,而生成函数往往是解决这类问题的重要工具。

    ​ 上面这句话出自2015年金策的论文,这篇论文写的非常系统,推荐阅读。

    ​ 本文则是偏向于推导和总结,分成组合数学部分和多项式全家桶 一点都不全 部分,分别讲解生成函数在解决组合计数问题的方法及技巧。

    组合数学

    概念

    生成函数

    ​ 生成函数就是一列用来展示一串数字的挂衣架。(赫伯特·维尔夫)

    ​ 在数学中,某个序列 ({displaystyle (a_{n})_{nin mathbb {N} }})母函数(又称生成函数,英语:Generating function)是一种形式幂级数,其每一项系数可以提供关于这个序列的信息。使用母函数解决问题的方法称为母函数方法。(维基百科)

    ​ 看完上面的解释,相信初次接触生成函数的读者也对它有了一定的了解 (扯吧 。生成函数按实现功能可以分成两类:普通型生成函数、指数型生成函数。

    普通型生成函数(OGF)

    ​ 对于一个给定的数列 ({a_n}) ,定义它的普通型生成函数 (G(x))

    [G(x)=sum_{n=0}^{+infty}a_nx^n ]

    ​ 如果这个数列是不是无穷数列,那么比最后一项高的项都为 (0)

    指数型生成函数(EGF)

    ​ 对于一个给定的数列 ({a_n}) ,定义它的指数型生成函数 (G(x))

    [G(x)=sum_{n=0}^{+infty}{a_nover n!}x^n ]

    ​ 如果这个数列是不是无穷数列,那么比最后一项高的项都为 (0)

    ​ 生成函数说白了就是把一个数列摆在一个形式幂级数上,而形式幂级数就是上面那个写成函数样子的 (G(x)) ,注意,它真的就只是一个形式,那个变量 (x) 不可能真的带一个数进去算。如果拿挂衣架做比喻的话,那 (x) 的不同幂次就相当于挂衣架上的一个一个钩子,数列 ({a_n}) 就是一件一件的衣服。钩子把一件一件衣服挂在挂衣架上,就是生成函数。

    ​ 我们不妨用几道烂大街的数学题来看一下生成函数这个东西的作用。

    例题
    • (例题 1-1-1)有 (1g) 砝码 (2) 枚,(2g) 砝码 (3) 枚,(3g) 砝码一枚,相同质量砝码之间没有区别,问称出每种质量的方案数。

    ​ 考虑生成函数,设 (x) 的指数为砝码的质量和,(F(x)) 为每种质量和的方案数的普通型生成函数,则

    [egin{align*} F(x)&=(1 + x + x^2)(1 + x^2 + x^4 + x^6)(1+x^3)\ &= 1 + x + 2 x^2 + 2 x^3 + 3 x^4 + 3 x^5 + 3 x^6 + 3 x^7 + 2 x^8 + 2 x^9 + x^{10} + x^{11} end{align*} ]

    ​ 其中每一个括号里的内容代表取每一种质量的砝码的情况,以第一个括号为例,(1)(即 (x^0) )代表不取 (1g)
    砝码,(x) 代表取 (1)(1g) 砝码,(x^2) 代表取 (2)(1g) 砝码。可以看出,生成函数的加法运算代表着“或”,而乘法运算则代表着“与”。

    • (例题 1-1-2)你有数字 (1) 两个,数字 (2) 三个, 数字 (3) 一个,问选出一个、两个、三个……数字的方案数。

    ​ 考虑生成函数,设 (x) 的指数为选出数字的个数,(F(x)) 为的不同个数的方案数的普通型生成函数,则

    [egin{align*} F(x)&=(1+x+x^2)(1+x+x^2+x^3)(1+x)\ &= 1 + 3x + 5x^2 + 6 x^3 + 5x^4 + 3x^5 + x^6 end{align*} ]

    ​ 本题的题面和上道题有点像,但是要求的东西不同,上道题要求的是每种质量和的方案数(即数字总和),而这道题是数字个数,定义状态不同,故生成函数不同。

    • (例题 1-1-3)你有数字 (1) 两个,数字 (2) 三个, 数字 (3) 一个,问组成一位数、两位数、三位数……的方案数。

    ​ 与上题的区别在于,位置有了标号,如 (123)(132) 为不同的情况。考虑生成函数,设 (x) 的指数为数字的位数,(F(x)) 为的不同位数的方案数的指数型生成函数,则

    [egin{align*} F(x)&=({1over 0!}+{1over 1!}x+{1over 2!}x^2)({1over 0!}+{1over 1!}x+{1over 2!}x^2+{1over 3!}x^3)({1over 0!}+{1over 1!}x)\ &={1 over 0!} + {3 over 1!} x + {8 over 2!} x^2 + {19 over 3!} x^3 + {38 over 4!} x^4 + {60 over 5!} x^5 + {60 over 6!} x^6 end{align*} ]

    ​ 指数型生成函数可能刚开始有点难以理解,初学者可能会发出这样的疑问:这个东西不就是 (x^n) 下面加了一个 (n!) 吗?是的,形式上就是这样的,在编程中,运算时也要把它转成普通型运算,再转成指数型展示。但是,与上面的问题对比一下,就不难发现一个规律:

    普通型生成函数解决的是组合问题(无标号),指数型生成函数解决的是排列问题(有标号)。

    ​ 这里面也没什么大道理,让我们观察其中一项的计算过程,以 (x^3) 为例,我们看一下那个 (19) 是怎么来的。

    [egin{align*} {19over 3!}&={1over 2!cdot 1!cdot 0!}+{1over 2!cdot 0!cdot 1!}+{1over 1!cdot 2!cdot 0!}+{1over 1!cdot 1!cdot 1!}+{1over 0!cdot 3!cdot 0!}+{1over 0!cdot 2!cdot 1!}\ 19&={3!over 2!cdot 1!cdot 0!}+{3!over 2!cdot 0!cdot 1!}+{3!over 1!cdot 2!cdot 0!}+{3!over 1!cdot 1!cdot 1!}+{3!over 0!cdot 3!cdot 0!}+{3!over 0!cdot 2!cdot 1!}\ 19&={3choose 2quad 1quad 0}+{3choose 2quad 0quad 1}+{3choose 1quad 2quad 0}+{3choose 1quad 1quad 1}+{3choose 0quad 3quad 0}+{3choose 0quad 2quad 1} end{align*} ]

    ​ 式子变一变,就变成了一个多重元素全排列的形式,例题 1-1-2 是对一样的数列构造一个普通型生成函数,([x^3]=6) ,(([x^n]) 表示取多项式中次数为 (n) 的项的系数)而 (displaystyle {19over 3!}) 展开也有 (6) 项,只是每一项多乘了排列数罢了。

    ​ 更一般的说,设原题三个括号中的生成函数分别为 (A(x),B(x),C(x)),有

    [F(x)={displaystylelargesum_{n=0}^{+infty}}sum_{i=0}^{+infty}sum_{j=0}^{+infty}sum_{k=0}^{+infty}[n=i+j+k]{nchoose iquad j quad k}a_ib_jc_kx^n ]

    ​ 对于有标号的组合对象,我们在转移时还要考虑不同的标号排列,于是我们在分母上添了阶乘,这样就可以帮助我们转移了。接下来,我们来了解一下“组合对象”这一名词。

    组合对象

    ​ 组合计数问题一般定义了一类组合对象 (A) ,它可能是满足某一类性质的树、图、串等对象的集合;其中每个对象 (a in A) 都被赋予了一个大小 ({ m size}(a) inmathbb N),它可能代表节点数,序列长度等。对于某个固定的 (n),满足 ({ m size}(a)=n) 的对象是有限的,记作 (A_n) 。我们的任务通常为求出 (A_n) 的数值。

    ​ 根据不同问题的要求,组合对象可以分为有标号和无标号两类。

    (论文)

    ​ 通过以 (A_n) 构造生成函数,我们得以将 ({ m size}(a))(x) 的指数对应,将 (A_{{ m size}(a)})(x) 的系数对应,从而求出我们想要的结果。

    ​ 在例题 1-1-1 中,不同砝码组合构成的集合就是我们要研究的组合对象,每一种砝码组合就是一个对象,对象 (a)( m size) 定义为这个砝码组合的质量和,(A_n) 表示的称出的质量和为 (n) 的方案数,该组合对象属于无标号组合对象;

    ​ 在例题 1-1-3 中,不同 (n) 位数( (n) 个数字的排列)构成的集合就是我们的组合对象,一个 (n) 位数就是一个对象,对象 (a)( m size) 定义为数的位数,(A_n) 表示构成 (n) 位数的方案数,该组合对象属于有标号组合对象。

    公式

    ​ 仅仅只是表示成几个式子的乘积只是生成函数最基本的部分,利用形式幂级数的变形进行推导才是比较有研究价值的地方,接下来,我们来展示一些基础而重要的公式。

    • 公式 ( m I)

    [displaystyle {1over 1-x} = sum_{n=0}^{+infty}x^n\ ]

    ​ 也被称作无穷递缩等比数列求和公式,由于收敛性,(xin(0,1)) 时式子成立,但由于本文讲的是生成函数,写出来的式子是形式幂级数,所以 (x) 不能代具体的数。

    ​ 把左边的分母乘到右边去就可以得证,或者直接套用等比数列求和公式证明。

    • 公式 ( m II)

    [quaddisplaystyle {1 over (1 -x)^k} = sum_{n=0}^infty{n+k-1choose k-1}x^n = sum_{n=0}^infty{n+k-1choose n}x^n ]

    ​ 可以由公式 ({ m I}) 两边同求 (k-1) 次导,再同除以 ((k-1)!) 得到。 也可以把式子转化为 ({ig(}(1-x)^{-1}{ig)}^k) ,用组合方法证明。

    • 公式 ( m{III}) (广义二项式定理)

    [(x + y)^alpha = sum_{n=0}^{+infty}{alpha choose n}x^ny^{alpha -n} ]

    ​ 其中 (displaystyle{alpha choose k}={alpha(alpha - 1)cdots(alpha - k + 1)over k!}={alpha^{{underline k}}over k!})

    ​ 可以利用广义二项式定理推导公式 ( m{I}) 和公式 ( m{II})

    • 公式 ( m{IV}) (泰勒展开)

    [f(x)=sum_{n=0}^infty {f^{(n)}(a)over n!}(x-a)^n ]

    ​ 表示 (f(x))(x=a) 处的泰勒展开,其中 (f^{(n)}) 表示 (f)(n) 阶导函数,其中 (a=0) 的情况被称作麦克劳林展开,形式如下:

    [f(x)=sum_{n=0}^infty {f^{(n)}(0)over n!}x^n ]

    • 公式 ( m V)

    [displaystyle e^{x} = sum_{n=0}^{+infty}{1over n!}x^n\ ]

    ​ 直接套用麦克劳林展开公式就可以得到,注意 (e^x) 的导数是它本身。

    应用

    ​ 接下来,我们来详细讲讲生成函数的应用,包括但不限于排列组合问题。

    基础构造

    ​ 在证明某些恒等式,或求某些数列的通项的时候,我们可以构造生成函数来解决。

    • (例题 2-1-1)证明 (displaystyle sum_{i=0}^k{nchoose i}{mchoose k-i}={n+mchoose k})

    ​ 上式即为范德蒙德卷积式。我们利用组合意义可以很容易得到证明,即在 (n) 个元素中选 (i) 个,在 (m) 个元素中选 (k-i) 个,当 (i) 取任意值时,这个方案数显然等于在 (n+m) 个元素中选 (k) 个。我们也可以用生成函数更加直观的表达上述组合意义,从而加以理性证明。

    ​ 对于 (n+m) 个物品,设 (x) 的指数为选出物品的个数,(F(x)) 为每种个数的方案数的普通型生成函数。分别从 (n) 个物品和 (m) 个物品中选,我们有以下式子

    [egin{align*}F(x)&=(1+x)^ncdot(1+x)^m\&=(sum_{i=0}^{+infty}{n choose i}x^i)cdot(sum_{i=0}^{+infty}{m choose i}x^i)\&=sum_{k=0}^{+infty}(sum_{i=0}^k{nchoose i}{mchoose k-i})x^kend{align*} ]

    ​ 而将 (n+m) 个物品当作整体,我们有以下式子

    [egin{align*}F(x)&=(1+x)^{n+m}\&=sum_{k=0}^{+infty}{n+m choose k}x^kend{align*} ]

    ​ 对照两式可得 (displaystyle sum_{i=0}^k{nchoose i}{mchoose k-i}={n+mchoose k}),即原命题得证。

    ​ 其实对于本题,我们也可以不考虑组合意义,直接由 ((1+x)^ncdot(1+x)^m=(1+x)^{n+m}) 这条等式,两边分别二项式展开证得所求结论。

    • (例题 2-1-2)证明 (displaystyle sum_{i=0}^n(-1)^i{nchoose i}^2= egin{cases}displaystyle 0&n为奇数\displaystyle(-1)^{nover 2}{nchoose {nover 2}}&n为偶数end{cases})

    ​ 这题不好看出其组合意义,但是求证的表达式和上题很相似,如果将原式看成 (displaystyle sum_{i=0}^n(-1)^i{n choose i}{nchoose n-i}),那么便很像范德蒙德卷积式了。类似的,我们设 (F(x)=(1-x)^ncdot(1+x)^n=(1-x^2)^n)

    [egin{align*} F(x)&=(1-x)^ncdot(1+x)^n\ &=(sum_{i=0}^{+infty}(-1)^i{n choose i}x^i)cdot(sum_{i=0}^{+infty}{n choose i}x^i)\ &=sum_{k=0}^{+infty}(sum_{i=0}^k(-1)^i{nchoose i}{nchoose k-i})x^k\\ F(x)&=(1-x^2)^n\ &=sum_{k=0}^n(-1)^k{nchoose k}x^{2k} end{align*} ]

    ​ 在上式中取 (k=n),下式中取 (displaystyle k={nover 2}) 即可得出结论。

  • 相关阅读:
    python 对xls写入信息
    Python 字符串前面加u,r,b,f的含义
    inner join 与 left join 之间的区别
    时间戳转换成日期展示的方法 且 搜索范围
    Python与C/C++相互调用(python2 调c++那个试了ok)
    爆库记录(X-Forwarded-For注入漏洞实战 记录)
    笔记
    墨者学习安全测试的网站(看起来很不错的样子 有空看看)
    sqlmap开源 测试sql注入的工具 各种参考链接
    菜鸟浅谈——web安全测试(这篇不错有空看看)
  • 原文地址:https://www.cnblogs.com/Paulliant/p/12054504.html
Copyright © 2011-2022 走看看