母函数(详细分析+例题讲解) 每日一遍,算法再见!
作者:互联网
母函数
母函数
一.普通母函数
在研究普通母函数之前,先看一个多项式,以便于更好的理解。
(
1
+
a
1
x
)
(
1
+
a
2
x
)
(
1
+
a
3
x
)
(
1
+
a
4
x
)
.
.
.
.
.
.
(
1
+
a
n
x
)
=
1
+
(
a
1
+
a
2
+
.
.
.
+
a
n
)
x
+
(
a
1
a
2
+
a
1
a
3
+
.
.
.
+
a
n
−
1
a
n
)
x
2
+
.
.
.
+
a
1
a
2
a
3
.
.
.
a
n
x
n
(1+a_1x)(1+a_2x)(1+a_3x)(1+a_4x)......(1+a_nx) = 1+(a_1+a_2+...+a_n)x+(a_1a_2+a_1a_3+...+a_{n-1}a_n)x^2+...+a_1a_2a_3...a_nx^n
(1+a1x)(1+a2x)(1+a3x)(1+a4x)......(1+anx)=1+(a1+a2+...+an)x+(a1a2+a1a3+...+an−1an)x2+...+a1a2a3...anxn.
我们由多项式可以看出
(1)
x
x
x项的系数是从n个数
(
a
1
,
a
2
,
a
3
,
.
.
.
,
a
n
)
(a_1,a_2,a_3,...,a_n)
(a1,a2,a3,...,an)中取一个数的组合起来的全体,有C(n,1)=n个。
(2) x 2 x^2 x2项的系数是从n个数 ( a 1 , a 2 , a 3 , . . . , a n ) (a_1,a_2,a_3,...,a_n) (a1,a2,a3,...,an)中取两个数的组合的全体,有C(n,2)个.
(3) x n x^n xn项的系数是从n个数 ( a 1 , a 2 , a 3 , . . . , a n ) (a_1,a_2,a_3,...,a_n) (a1,a2,a3,...,an)中取n个数的组合的全体,有C(n,n)=1个.
于是按照上面的规律,我们可以得到这个多项式的表达式
(
1
+
x
)
n
=
1
+
C
(
n
,
1
)
x
+
C
(
n
,
2
)
x
2
+
.
.
.
+
C
(
n
,
n
)
x
n
(1+x)^n =1+C(n,1)x+C(n,2)x^2+...+C(n,n)x^n
(1+x)n=1+C(n,1)x+C(n,2)x2+...+C(n,n)xn.
我们把上述式字改写成
G
(
x
)
=
(
1
+
x
)
n
=
1
+
a
1
x
+
a
2
x
2
+
a
3
x
3
.
.
.
+
a
n
x
n
G(x)=(1+x)^n = 1+a_1x+a_2x^2+a_3x^3...+a_nx^n
G(x)=(1+x)n=1+a1x+a2x2+a3x3...+anxn,其中ai=C(n,i),1<=i<=n.
我们讲函数G(x)是序列
a
1
,
a
2
,
a
3
,
.
.
.
,
a
n
a_1,a_2,a_3,...,a_n
a1,a2,a3,...,an的母函数。
例如G(x) = ( 1 + x ) n (1+x)^n (1+x)n是序列 C ( n , 1 ) , C ( n , 2 ) , . . . , C ( n , n ) C(n,1),C(n,2),...,C(n,n) C(n,1),C(n,2),...,C(n,n)的母函数
例1.有质量1,2,3的砝码各一枚,问:
(1)可以称出多少中不同质量的物品?
(2)要称出质量为3的物品,有多少种方案?
解:一个1g的砝码我们可以用 1 + x 1+x 1+x表示,其中1表示不用1g的砝码, x x x表示用1g的砝码。
同理,一个2g砝码我们可以用 1 + x 2 1+x^2 1+x2表示,其中1表示不用2g的砝码, x 2 x^2 x2表示用2g的砝码。
同理,一个3g砝码我们可以用 1 + x 3 1+x^3 1+x3表示,其中1表示不用3g的砝码, x 3 x^3 x3表示用3g的砝码。
那么母函数 G ( x ) = ( 1 + x ) ( 1 + x 2 ) ( 1 + x 3 ) = 1 + x + x 2 + 2 x 3 + x 4 + x 5 + x 6 G(x) = (1+x)(1+x^2)(1+x^3)=1+x+x^2+2x^3+x^4+x^5+x^6 G(x)=(1+x)(1+x2)(1+x3)=1+x+x2+2x3+x4+x5+x6 ,我们发现可以称出1~6g的物品,其中x前面的系数就是称出这种重量的方案数,比如 2 x 3 2x^3 2x3,x的指数是3,系数为2,表示能称出质量为3g的方案数有2种。
那么我们假设1g,2g,3g的砝码都有无数个,那么这样的母函数会是什么样子呢?
所构造的母函数如下: G ( x ) = ( 1 + x + x 2 + x 3 + . . + x n ) ( 1 + x 2 + x 4 + . . . + x n ) ( 1 + x 3 + x 6 + . . . + x n ) . . . G(x) = (1+x+x^2+x^3+..+x^n)(1+x^2+x^4+...+x^n)(1+x^3+x^6+...+x^n)... G(x)=(1+x+x2+x3+..+xn)(1+x2+x4+...+xn)(1+x3+x6+...+xn)...,其中第一个括号中 ( 1 + x + x 2 + x 3 + . . + x n ) , 1 表 示 取 0 个 1 g 的 砝 码 , x 表 示 取 1 个 1 g 的 砝 码 , x 2 表 示 取 2 个 1 g 的 砝 码 . . . 依 次 类 推 (1+x+x^2+x^3+..+x^n),1表示取0个1g的砝码,x表示取1个1g的砝码,x^2表示取2个1g的砝码...依次类推 (1+x+x2+x3+..+xn),1表示取0个1g的砝码,x表示取1个1g的砝码,x2表示取2个1g的砝码...依次类推,那么第二个括号中 ( 1 + x 2 + x 4 + . . . + x n ) , 1 表 示 取 0 个 2 g 的 砝 码 , x 2 表 示 取 1 个 2 g 的 砝 码 , x 4 表 示 取 2 个 2 g 的 砝 码 . . . . 依 次 类 推 (1+x^2+x^4+...+x^n),1表示取0个2g的砝码,x^2表示取1个2g的砝码,x^4表示取2个2g的砝码....依次类推 (1+x2+x4+...+xn),1表示取0个2g的砝码,x2表示取1个2g的砝码,x4表示取2个2g的砝码....依次类推。
下面我们来做一道例题
练习题1
2006/1/15 ACM程序设计期末考试
解题思路:我们按照题意构造出一个母函数G(x),然后我们只需要求出G(x)的所有x的指数小于等于50的系数之和就是答案.
母函数构造如下: G ( x ) = ( 1 + x + x 2 + . . . + x x 1 ) ( 1 + x 2 + x 4 + . . . + x 2 x 2 ) ( 1 + x 3 + x 6 + . . . + x 3 x 3 . . . . ( 1 + x 26 + x 52 + . . . + x 26 x 26 ) ) G(x) = (1+x+x^2+...+x^{x_1})(1+x^2+x^4+...+x^{2x_2})(1+x^3+x^6+...+x^{3x_3}....(1+x^{26}+x^{52}+...+x^{26x_{26}})) G(x)=(1+x+x2+...+xx1)(1+x2+x4+...+x2x2)(1+x3+x6+...+x3x3....(1+x26+x52+...+x26x26))
AC代码:
#include<bits/stdc++.h>
using namespace std;
int a[60]={0},b[50]={0};
int main()
{
int n;
cin>>n;
while(n--)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
a[0]=1;
for(int i=1;i<=26;i++)
{
int num;
cin>>num;
if(num==0) continue;
for(int j=0;j<=50;j++)
{
for(int k=0;k<=num&&k*i+j<=50;k++)
{
b[k*i+j]+=a[j];
}
}
for(int i=0;i<=50;i++)
{
a[i]=b[i];
b[i]=0;
}
}
int sum=0;
for(int i=1;i<=50;i++) sum+=a[i];
cout<<sum<<'\n';
}
return 0;
}
练习题2(整数的拆分)
Ignatius and the Princess III
题目大意:给你一个正整数N,我们定义一个等式
N=a[1]+a[2]+a[3]+…+a[m],a[i]>0,且1<=m<=N.问题是给你一个正整数N,有多少种不同的等式,例如4=1+3
4=1+1+1+1
4=2+2
4=4
4=2+1+1,一共有5种
思路:构造母函数G(x),然后
x
N
x^N
xN前面的系数就是方案数
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
ll a[200]={0},b[200]={0};
int main()
{
int n;
while(cin>>n)
{
// cin>>n;
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
a[0]=1;
for(int i=1;i<=n;i++)
{
int num=n/i;
for(int j=0;j<=n;j++)
for(int k=0;k<=num&&k*i+j<=n;k++)
{
b[k*i+j]+=a[j];
}
for(int j=0;j<=n;j++)
{
a[j]=b[j];
b[j]=0;
}
}
cout<<a[n]<<'\n';
}
return 0;
}
二.Ferrers图像
定义:一个从上到下的n层组成的图像,其中第i层有
m
i
m_i
mi格子,并且保证
m
i
>
=
m
i
+
1
m_i>=m_{i+1}
mi>=mi+1。就像下图这样
然后我们发现把这张图顺时针旋转90度也是一个Ferrers图像,就像下面这样,我们称这两张图为一对共轭的Ferrers图像。
我们可以通过研究Ferrers图像得到一些性质
定理:整数N拆分成k个数的和的拆分方案数(简称拆分数),与数N拆分成最大数为k的拆分数相同。
例如,我们令N=34,分解k=5,那么
图一.
这图一就表示34 = 6+6+5+4+3,一共5个数
图二(图一的共轭Ferrers图).
图二就表示了,N=5+5+5+4+3+2,最大数为5.
故定理2:整数N拆分成不超过m的拆分数,与拆分成最大数不超过m的拆分数相同。
三.指数母函数
指数型母函数问题:
假设有n个元素,其中a1,a2,····,an互不相同,进行全排列,可得n!个不同的排列。若其中某一元素a1重复了n1次,全排列出来必有重复元素,其中真正不同的排列数应为n!/n1!,即其重复度为n1!
同样理由a1重复了n1次,a2重复了n2次,····,ak重复了nk次,n1+n2+····+nk=n。对于这样的n个元素进行全排列,可得不同排列的个数实际上是
上面的问题是从n个元素中选n个元素(也就是全部选)的排列,那么如果要求从n个元素中选r个的排列有多少种怎么求呢?这里就要用到指数母函数了
定义:
我们发现指数母函数和普通母函数只有一个地方不同,那就是x前面的系数,普通母函数系数是
a
i
a_i
ai的表示形式,而指数母函数系数是
a
i
i
!
\frac{a_i}{i!}
i!ai的表示形式。下面我们来看看指数形母函数能够解决什么样的问题。
例3.有1,2,3,4四个数字的组成的五位数,要求1出现次数不超过2次,但不能不出现;2出现次数不超过1次;3出现的次数最多3次,可以不出现;4出现次数为偶数,求满足上述条件的数的个数。
问题分析:想当于是从1,2,3,4四个数中可重复的选5个数组成的排列数,但是每个数字有选取限制条件。
所以我们构造出指数母函数
能够看到
x
5
5
!
\frac{x^5}{5!}
5!x5前面的系数是215,所以一共有215种情况。
练习题3
排列组合HDU-1521
这就是一道典型的指数母函数的板子题。
分析:我们构造出指数母函数
AC代码:
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double a[200],b[200];
int f(int n)
{
int ans=1;
for(int i=1;i<=n;i++) ans*=i;
return ans;
}
int num[20];
int main()
{
int n,m;
while(cin>>n>>m)
{
memset(a,0,sizeof(a));
memset(b,0,sizeof(b));
for(int i=1;i<=n;i++) cin>>num[i];
for(int i=0;i<=num[1];i++)
{
a[i]=1.0/f(i);
}
for(int i=2;i<=n;i++)
{
for(int j=0;j<=m;j++)
for(int k=0;k<=num[i]&&k+j<=m;k++)
{
b[k+j]+=a[j]/f(k);
}
for(int i=0;i<=m;i++)
{
a[i]=b[i];
b[i]=0;
}
}
printf("%.0lf\n",a[m]*f(m));
}
return 0;
}
标签:...,+...+,函数,int,砝码,讲解,x2,详细分析,例题 来源: https://blog.csdn.net/TheWayForDream/article/details/114186470