快乐地打牢基础(13)——普通型母函数和指数型母函数的应用

母函数就是一列用来展示一串数字的挂衣架。 ——赫伯特·唯尔夫 。

一、普通型母函数


1.定义

对于任意数列 a 0 , a 1 , a 2 . . . a n a_0,a_1,a_2...a_n ,用如下方法与一个函数联系起来:
G ( x ) = a 0 + a 1 x + a 2 x 2 + . . . + a n x n G(x) = a_0+a_1x+a_2x^2+...+a_nx^n
则称 G ( x ) G(x) 是数列的母函数(generating function)(也叫生成函数)。
其一般形式为:
G ( a n ; x ) = i = 1 a i x i \displaystyle G(a_n;x)=\sum_{i=1}a_ix^i

2.应用

组合数学的主要内容是计数,母函数是组合数学中的一个重要理论和工具。那么它是怎么应用的呢?

普通型母函数主要是解决求有限多重集的组合

设元素 a 1 , a 1 , , a n a_{1},a_{1}, \cdot \cdot \cdot ,a_{n} 互不相同,从有限多重集 { K 1 a 1 , K 2 a 2 , K n a n } \left\{ K_{1} \cdot a_{1},K_{2} \cdot a_{2}, \cdot \cdot \cdot K_{n} \cdot a_{n} \right\} 中选取 r r 个元素,至少存在一个 K i < r K_{i} < r 时,求其组合。

下面举一个应用实例来理解这个问题:

现在我有两个色子,每个色子有六个面,每个色子掷一次,问两个色子投掷后加起来一共六点的情况有多少种?

我们数一数,根据加法原理:

  • 6 = 1 + 5 = 5 +1
  • 6= 2 + 4 = 4 + 2
  • 6 = 3 + 3

根据乘法原理

  • 第一次取 1,2,3,4,5 共五种方式
  • 由于第一次已经取好,所以第二次的取法是固定的 只有一种

综上,加起来点数为 6 一共是 五 种。

但是如果有 n n 个色子呢?显然就很难这样计算出来了

我们这时就需要母函数了。
我们可以 x , x 2 , x 3 , x 4 , x 5 , x 6 x,x^2,x^3,x^4,x^5,x^6 和 色子的 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 点映射对应起来。

按照乘法原理,我们可以将两次 色子的投掷看成是 两个 多项式相乘。
例如 投掷 6 点
第一次 投的 是 4 点,第二次是 2 点。和 x 4 x 2 = x 6 x^4 x^2=x^6 对应起来。

那么第一次投掷可能取 1 , 2 , 3 , 4 , 5 , 6 1,2,3,4,5,6 点,这些情况是不可能同时发生的,那么根据加法原理:
第一次投掷就可以和 多项式 ( x + x 2 + x 3 + x 4 + x 5 + x 6 ) (x+x^2+x^3+x^4+x^5+x^6) 形成一个映射关系, x i x^i 就表示投掷出了 i i 点。
那么两次投掷的过程就能表示为两个多项式的乘积:
( x + x 2 + x 3 + x 4 + x 5 + x 6 ) ( x + x 2 + x 3 + x 4 + x 5 + x 6 ) (x+x^2+x^3+x^4+x^5+x^6)*(x+x^2+x^3+x^4+x^5+x^6)
乘积的结果是
x 2 + 2 x 3 + 3 x 4 + 4 x 5 + 5 x 6 + 6 x 7 + 5 x 8 + 4 x 9 + 3 x 10 + 2 x 11 + x 12 x^2+2x^3+3x^4+4x^5+5x^6+6x^7+5x^8+4x^9+3x^{10}+2x^{11}+x^{12}
x 6 : x 1 x 5 + x 2 + x 4 + x 3 x 3 + x 4 x 2 + x 5 x 1 = 5 x 6 x^6:x^1x^5+x^2+x^4+x^3x^3+x^4x^2+x^5x^1=5x^6

我们发现 x 6 x^6 的系数就是两次投掷点数和为 6 的方法数。

到此我们可以得到一个结论:

投掷 m m 粒色子时,加起来点数的综合化等于 n n 的可能方式的数目为:
G ( x ) = ( x + x 2 + x 3 + x 4 + x 5 + x 6 ) m G(x)=(x+x^2+x^3+x^4+x^5+x^6)^m
展开式中 x n x^n 的系数。

很明显 G ( x ) G(x) 就是序列 { 1 , 2 , 3 , 4 , 5 , 6 } \{1,2,3,4,5,6\} 的一个母函数,这个例子也很好的说明了母函数的应用:

将计数问题映射成多项式的乘法运算来解决

HDU 1028 Ignatius and the Princess II
题意

给定一个数 N N ,问 N N 拆成若干个整数有多少中拆分方法?

思路
使用母函数进行映射
取 0 个 1 1 : x 0 x^0
取 1 个 1 1 : x 1 x^1
取 2 个 1 1 : x 2 x^2
1 1 对应的母函数: ( 1 + x + x 2 + . . . + x k + . . . ) (1+x+x^2+...+x^k+...)
2 2 对应的母函数: ( 1 + x 1 + x 4 + . . . + x 2 k . . . ) (1+x^1+x^4+...+x^{2k}...)
G ( x ) = ( 1 + x + x 2 + . . . ) ( 1 + x 2 + x 4 + . . . ) ( 1 + x 2 + x 4 + . . . ) ( 1 + x N ) G(x) = (1+x+x^2+...)(1+x^2+x^4+...)(1+x^2+x^4+...)(1+x^N)

x N x^N 的系数就是 我们要求的答案。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;

const int N = 1000;
ll a[N],b[N];
int n;

void mother_fun()
{
    a[0] = 1;
    for(int i = 1; i <= n ; i++)
    {
        memset(b,0,sizeof(b));
        for(int j = 0; j * i <= n; j++)
        {
            for(int k = 0; k <= n; k++)
            {
                b[i * j + k] += a[k] ;
            }
        }
        memcpy(a,b,sizeof(b));
   }
}
int main()
{
    while(scanf("%d",&n)!= EOF)
    {
        memset(a,0,sizeof(a));
        mother_fun();
        printf("%lld\n",a[n]);
    }
    return 0;
}

二、指数型母函数

1.定义

序列 a 1 , a 2 , . . . , a n a_1,a_2,...,a_n 的指数型母函数为:
E G ( a n ; x ) = i = 0 a i x i i ! \displaystyle EG(a_n;x)=\sum_{i = 0}a_i\frac{x^i}{i!}

2.应用

从上面的学习,我们可以知道:普通型的母函数是一个解决求有限多重集的组合的有效工具,而指数型函数是
指数型母函数主要是解决求有限多重集的排列
设元素 a 1 , a 1 , , a n a_{1},a_{1}, \cdot \cdot \cdot ,a_{n} 互不相同,从有限多重集 { K 1 a 1 , K 2 a 2 , K n a n } \left\{ K_{1} \cdot a_{1},K_{2} \cdot a_{2}, \cdot \cdot \cdot K_{n} \cdot a_{n} \right\} 中选取 r r 个元素,至少存在一个 K i < r K_{i} < r 时,求其排列。

我们比较普通型母函数和指数型母函数,可以看出普通型的母函数的标志函数为 1 , x , x 2 , . . . , x n 1,x,x^2,...,x^n ;而指数型函数的标志函数为 1 , x / 1 ! , x 2 / 2 ! , x 3 / 3 ! . . . , x n / n ! 1,x/1!,x^2/2!,x^3/3!...,x^n/n!
这样的映射也有其意义:

x i i ! \displaystyle\frac{x^i}{i!} 代表的意义是:在某个方案中某个元素出现了 i i 次,而在不同位置中的 i i 次出现是相同的。

另外,在指数型母函数使用的过程中,一般都会用到高等数学里的 e x e^x 的泰勒展开式:
e x = n = 0 x n n ! = 1 + x + x 2 2 ! + x 3 3 ! . . . + x n n ! + . . . e^x=\sum_{n=0}\frac{x^n}{n!}=1 + x+\frac{x^2}{2!}+\frac{x^3}{3!}...+\frac{x^n}{n!}+...
( e x + e x ) / 2 = n = 0 x 2 n 2 n ! = 1 + x 2 2 ! + x 4 4 ! . . . + x 2 n 2 n ! + . . . (e^x+e^{-x})/2=\sum_{n=0}\frac{x^{2n}}{2n!}=1 +\frac{x^2}{2!}+\frac{x^4}{4!}...+\frac{x^{2n}}{2n!}+...
( e x e x ) / 2 = n = 0 x 2 n + 1 ( 2 n + 1 ) ! = x + x 3 3 ! + x 5 5 ! . . . + x 2 n + 1 ( 2 n + 1 ) ! + . . . (e^x-e^{-x})/2=\sum_{n=0}\frac{x^{2n+1}}{(2n+1)!}= x+\frac{x^3}{3!}+\frac{x^5}{5!}...+\frac{x^{2n+1}}{(2n+1)!}+...
下面来举个例子:

1 , 2 , 3 , 4 1,2,3,4 四个数字组成的五位数中,要求数 1 1 出现两次或三次, 2 2 最多出现一次, 4 4 出现偶数次。

这很明显是一个排列数的问题,在我们有了上述普通型母函数的经验之后,我们可以类似地开始构造我们的指数型母函数:

  1. 1 1 出现两次或三次,对应的母函数: x 2 2 ! + x 3 3 ! \displaystyle\frac{x^2}{2!}+\frac{x^3}{3!}

  2. 2 2 最多出现 一次,对应的母函数: 1 + x 1 ! \displaystyle1+\frac{x}{1!}

  3. 3 3 出现没有要求, 1 + x 1 ! + x 2 2 ! + x 3 3 ! + . . . + x n n ! + . . . \displaystyle1+ \frac{x}{1!}+ \frac{x^2}{2!} +\frac{x^3}{3!}+...+\frac{x^{n}}{n!}+...

  4. 4 4 出现偶数次, 1 + x 2 2 ! + x 4 4 ! + x 6 6 ! . . . + x 2 n 2 n ! + . . . \displaystyle1+\frac{x^2}{2!} +\frac{x^4}{4!}+\frac{x^6}{6!}...+\frac{x^{2n}}{2n!}+...

那么本题的母函数:
G ( x ) = ( x 2 2 ! + x 3 3 ! ) ( 1 + x 1 ! ) ( 1 + x 1 ! + x 2 2 ! + x 3 3 ! + . . . + x n n ! + . . . ) ( 1 + x 2 2 ! + x 4 4 ! + x 6 6 ! . . . + x 2 n 2 n ! + . . . ) \displaystyle G(x) = (\frac{x^2}{2!}+\frac{x^3}{3!})*(1+\frac{x}{1!})*(1+ \frac{x}{1!}+ \frac{x^2}{2!} +\frac{x^3}{3!}+...+\frac{x^{n}}{n!}+...)*(1+\frac{x^2}{2!} +\frac{x^4}{4!}+\frac{x^6}{6!}...+\frac{x^{2n}}{2n!}+...)

因为, e x = n = 0 x n n ! = 1 + x + x 2 2 ! + x 3 3 ! . . . + x n n ! + . . . e^x=\sum_{n=0}\frac{x^n}{n!}=1 + x+\frac{x^2}{2!}+\frac{x^3}{3!}...+\frac{x^n}{n!}+...
( e x + e x ) / 2 = n = 0 x 2 n 2 n ! = 1 + x 2 2 ! + x 4 4 ! . . . + x 2 n 2 n ! + . . . (e^x+e^{-x})/2=\sum_{n=0}\frac{x^{2n}}{2n!}=1 +\frac{x^2}{2!}+\frac{x^4}{4!}...+\frac{x^{2n}}{2n!}+...

所以
G ( x ) = ( x 2 2 ! + x 3 3 ! ) ( 1 + x 1 ! ) e x ( e x + e x ) / 2 G(x)=(\frac{x^2}{2!}+\frac{x^3}{3!})*(1+\frac{x}{1!})*e^x*(e^x+e^{-x})/2
= ( x 2 4 + x 3 3 + x 4 12 ) ( e 2 x + 1 ) =\displaystyle(\frac{x^2}{4}+\frac{x^3}{3}+\frac{x^4}{12})*(e^{2x}+1)
我们要求的是 5 5 位数,那么我们的答案就应该是 x 5 5 ! \displaystyle\frac{x^5}{5!} 前面的系数。
我们已经有了 x 2 , x 3 , x 4 x^2,x^3,x^4 ,所以只需要补上 x 3 , x 2 , x 1 x^3,x^2,x^1

e 2 x e^{2x} 按泰勒展开后,可以得到系数是:

5 ! ( 1 4 2 3 3 ! + 1 2 2 2 2 ! + 1 12 2 1 1 ! ) = 140 5!*(\frac{1}{4}*\frac{2^3}{3!}+\frac{1}{2}*\frac{2^2}{2!}+\frac{1}{12}*\frac{2^1}{1!})=140

HDU 1521 排列组合
题意

有n种物品,并且知道每种物品的数量。要求从中选出m件物品的排列数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有"AB","BA"两种。

思路

根据题意,这是一个多重集的排列数问题,所以考虑使用指数型生成函数,然后就是一顿模板。

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
#define ll long long
using namespace std;

const int N = 107;
int n,m;
int num[N];
double a[N] = {0},b[N] = {0};
//求阶乘
int fac(int n) {
	int res = 1;
	for(int i = 1; i <= n; i++) res *= i;
	return res;
}
//指数型母函数
void mother_fun() {
	for(int i = 0; i <= num[1]; i++) a[i] = 1.0 / fac(i);
	for(int cur = 2; cur <= n; cur++) {
		memset(b,0,sizeof(b));
		for(int i = 0 ; i <= num[cur]; i++) {
			for(int k = 0; k  + i <= m; k++) {
				b[i + k] += a[k] / fac(i) ;
			}
		}
		memcpy(a,b,sizeof(b));
	}
	printf("%.0lf\n",a[m]*fac(m));
}
int main() {
	//freopen("data.in","r",stdin);
	while(scanf("%d%d",&n,&m)!= EOF) {
		memset(a,0,sizeof(a));
		for(int i = 1; i <= n; i++) scanf("%d",num + i);
		mother_fun();
	}
	return 0;
}

发布了141 篇原创文章 · 获赞 71 · 访问量 6万+

猜你喜欢

转载自blog.csdn.net/sinat_40872274/article/details/102477523