母函数就是一列用来展示一串数字的挂衣架。 ——赫伯特·唯尔夫 。
一、普通型母函数
1.定义
对于任意数列
a
0
,
a
1
,
a
2
.
.
.
a
n
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 ) = a 0 + a 1 x + a 2 x 2 + . . . + a n x n 则称
G
(
x
)
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
G ( a n ; x ) = i = 1 ∑ a i x i
2.应用
组合数学的主要内容是计数,母函数是组合数学中的一个重要理论和工具。那么它是怎么应用的呢?
普
通
型
母
函
数
主
要
是
解
决
求
有
限
多
重
集
的
组
合
普通型母函数主要是解决求有限多重集的组合
普 通 型 母 函 数 主 要 是 解 决 求 有 限 多 重 集 的 组 合
设元素
a
1
,
a
1
,
⋅
⋅
⋅
,
a
n
a_{1},a_{1}, \cdot \cdot \cdot ,a_{n}
a 1 , a 1 , ⋅ ⋅ ⋅ , 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\}
{ K 1 ⋅ a 1 , K 2 ⋅ a 2 , ⋅ ⋅ ⋅ K n ⋅ a n } 中选取
r
r
r 个元素,至少存在一个
K
i
<
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
n 个色子呢?显然就很难这样计算出来了
我们这时就需要母函数了。 我们可以
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 和 色子的
1
,
2
,
3
,
4
,
5
,
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
x 4 x 2 = x 6 对应起来。
那么第一次投掷可能取
1
,
2
,
3
,
4
,
5
,
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 + x 2 + x 3 + x 4 + x 5 + x 6 ) 形成一个映射关系,
x
i
x^i
x i 就表示投掷出了
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 + 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 2 + 2 x 3 + 3 x 4 + 4 x 5 + 5 x 6 + 6 x 7 + 5 x 8 + 4 x 9 + 3 x 1 0 + 2 x 1 1 + x 1 2
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 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^6
x 6 的系数就是两次投掷点数和为 6 的方法数。
到此我们可以得到一个结论:
投掷
m
m
m 粒色子时,加起来点数的综合化等于
n
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
G ( x ) = ( x + x 2 + x 3 + x 4 + x 5 + x 6 ) m 展开式中
x
n
x^n
x n 的系数。
很明显
G
(
x
)
G(x)
G ( x ) 就是序列
{
1
,
2
,
3
,
4
,
5
,
6
}
\{1,2,3,4,5,6\}
{ 1 , 2 , 3 , 4 , 5 , 6 } 的一个母函数,这个例子也很好的说明了母函数的应用:
将计数问题映射成多项式的乘法运算来解决
HDU 1028 Ignatius and the Princess II 题意
给定一个数
N
N
N ,问
N
N
N 拆成若干个整数有多少中拆分方法?
思路 使用母函数进行映射 取 0 个
1
1
1 :
x
0
x^0
x 0 取 1 个
1
1
1 :
x
1
x^1
x 1 取 2 个
1
1
1 :
x
2
x^2
x 2 取
1
1
1 对应的母函数:
(
1
+
x
+
x
2
+
.
.
.
+
x
k
+
.
.
.
)
(1+x+x^2+...+x^k+...)
( 1 + x + x 2 + . . . + x k + . . . ) 取
2
2
2 对应的母函数:
(
1
+
x
1
+
x
4
+
.
.
.
+
x
2
k
.
.
.
)
(1+x^1+x^4+...+x^{2k}...)
( 1 + x 1 + x 4 + . . . + x 2 k . . . )
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)
G ( x ) = ( 1 + x + x 2 + . . . ) ( 1 + x 2 + x 4 + . . . ) ( 1 + x 2 + x 4 + . . . ) ( 1 + x N )
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
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!}
E G ( a n ; x ) = i = 0 ∑ a i i ! x i
2.应用
从上面的学习,我们可以知道:普通型的母函数是一个解决求有限多重集的组合的有效工具,而指数型函数是
指
数
型
母
函
数
主
要
是
解
决
求
有
限
多
重
集
的
排
列
指数型母函数主要是解决求有限多重集的排列
指 数 型 母 函 数 主 要 是 解 决 求 有 限 多 重 集 的 排 列 设元素
a
1
,
a
1
,
⋅
⋅
⋅
,
a
n
a_{1},a_{1}, \cdot \cdot \cdot ,a_{n}
a 1 , a 1 , ⋅ ⋅ ⋅ , 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\}
{ K 1 ⋅ a 1 , K 2 ⋅ a 2 , ⋅ ⋅ ⋅ K n ⋅ a n } 中选取
r
r
r 个元素,至少存在一个
K
i
<
r
K_{i} < r
K i < r 时,求其排列。
我们比较普通型母函数和指数型母函数,可以看出普通型的母函数的标志函数为
1
,
x
,
x
2
,
.
.
.
,
x
n
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!
1 , x / 1 ! , x 2 / 2 ! , x 3 / 3 ! . . . , x n / n ! 。 这样的映射也有其意义:
x
i
i
!
\displaystyle\frac{x^i}{i!}
i ! x i 代表的意义是:在某个方案中某个元素出现了
i
i
i 次,而在不同位置中的
i
i
i 次出现是相同的。
另外,在指数型母函数使用的过程中,一般都会用到高等数学里的
e
x
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 = n = 0 ∑ n ! x n = 1 + x + 2 ! x 2 + 3 ! x 3 . . . + n ! x 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 ∑ 2 n ! x 2 n = 1 + 2 ! x 2 + 4 ! x 4 . . . + 2 n ! x 2 n + . . .
(
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)!}+...
( e x − e − x ) / 2 = n = 0 ∑ ( 2 n + 1 ) ! x 2 n + 1 = x + 3 ! x 3 + 5 ! x 5 . . . + ( 2 n + 1 ) ! x 2 n + 1 + . . . 下面来举个例子:
由
1
,
2
,
3
,
4
1,2,3,4
1 , 2 , 3 , 4 四个数字组成的五位数中,要求数
1
1
1 出现两次或三次,
2
2
2 最多出现一次,
4
4
4 出现偶数次。
这很明显是一个排列数的问题,在我们有了上述普通型母函数的经验之后,我们可以类似地开始构造我们的指数型母函数:
1
1
1 出现两次或三次,对应的母函数:
x
2
2
!
+
x
3
3
!
\displaystyle\frac{x^2}{2!}+\frac{x^3}{3!}
2 ! x 2 + 3 ! x 3
2
2
2 最多出现 一次,对应的母函数:
1
+
x
1
!
\displaystyle1+\frac{x}{1!}
1 + 1 ! x
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!}+...
1 + 1 ! x + 2 ! x 2 + 3 ! x 3 + . . . + n ! x 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!}+...
1 + 2 ! x 2 + 4 ! x 4 + 6 ! x 6 . . . + 2 n ! x 2 n + . . .
那么本题的母函数:
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!}+...)
G ( x ) = ( 2 ! x 2 + 3 ! x 3 ) ∗ ( 1 + 1 ! x ) ∗ ( 1 + 1 ! x + 2 ! x 2 + 3 ! x 3 + . . . + n ! x n + . . . ) ∗ ( 1 + 2 ! x 2 + 4 ! x 4 + 6 ! x 6 . . . + 2 n ! x 2 n + . . . )
因为,
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 = n = 0 ∑ n ! x n = 1 + x + 2 ! x 2 + 3 ! x 3 . . . + n ! x 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 ∑ 2 n ! x 2 n = 1 + 2 ! x 2 + 4 ! x 4 . . . + 2 n ! x 2 n + . . .
所以
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
G ( x ) = ( 2 ! x 2 + 3 ! x 3 ) ∗ ( 1 + 1 ! x ) ∗ 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)
= ( 4 x 2 + 3 x 3 + 1 2 x 4 ) ∗ ( e 2 x + 1 ) 我们要求的是
5
5
5 位数,那么我们的答案就应该是
x
5
5
!
\displaystyle\frac{x^5}{5!}
5 ! x 5 前面的系数。 我们已经有了
x
2
,
x
3
,
x
4
x^2,x^3,x^4
x 2 , x 3 , x 4 ,所以只需要补上
x
3
,
x
2
,
x
1
x^3,x^2,x^1
x 3 , x 2 , x 1
将
e
2
x
e^{2x}
e 2 x 按泰勒展开后,可以得到系数是:
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
5 ! ∗ ( 4 1 ∗ 3 ! 2 3 + 2 1 ∗ 2 ! 2 2 + 1 2 1 ∗ 1 ! 2 1 ) = 1 4 0
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 ( ) {
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 ;
}