1.指数型母函数的定义
对于一个序列 a 0 , a 1 , a 2 ⋅ ⋅ ⋅ ⋅ a n a^0,a^1,a^2\cdot\cdot\cdot\cdot a^n a0,a1,a2⋅⋅⋅⋅an,我们称 a 0 0 ! + a 1 1 ! ⋅ x 1 + a 2 2 ! ⋅ x 2 + a 3 3 ! ⋅ x 3 + ⋅ ⋅ ⋅ + a n n ! ⋅ x n \frac{a_0}{0!}+\frac{a_1}{1!}\cdot x^1+\frac{a_2}{2!}\cdot x^2 +\frac{a_3}{3!}\cdot x^3+\cdot\cdot\cdot+\frac{a_n}{n!}\cdot x^n 0!a0+1!a1⋅x1+2!a2⋅x2+3!a3⋅x3+⋅⋅⋅+n!an⋅xn为该序列的指数型母函数
指数型母函数算是普通型母函数的延伸,不太懂母函数的可以先看这个,普通型母函数
2.多重集排列问题
有n种物体,给出每种物体的数量,现从中选出m个进行排列,问你排列方案有多少种。
3.指数型母函数求解多重集排列问题
证明过程点这里
过程很详细。
如何构造指数型母函数:
以三种物体,分别有2,2,3个为例,
则可构造如下母函数:
( 1 + x 1 1 ! + x 2 2 ! ) ⋅ ( 1 + x 1 1 ! + x 2 2 ! ) ⋅ ( 1 + x 1 1 ! + x 2 2 ! + x 3 3 ! ) (1+\frac{x^1}{1!}+\frac{x^2}{2!})\cdot(1+\frac{x^1}{1!}+\frac{x^2}{2!})\cdot(1+\frac{x^1}{1!}+\frac{x^2}{2!}+\frac{x^3}{3!}) (1+1!x1+2!x2)⋅(1+1!x1+2!x2)⋅(1+1!x1+2!x2+3!x3)
解释:
一个括号内的内容为一个多项式,第一个多项式代表第一种物品的选取情况,每一项的指数代表选取个数,如 x 2 x^2 x2代表第一种物品选两次,那么第一个多项式就涵盖了第一种物品的所有选取情况(0,1,2)。
第二个多项式同理,第三个多项式多了一项,因为第三种物体有3个,多一种选择的情况。
与普通型母函数对比:
①每一个多项式的指数都是连续的(因为指数代表的意义不同了,普通型母函数用指数代表权值,这里用指数代表选取个数)
②分母多了个阶乘,原因可见上面的链接,内有证明过程
求解:
构造完之后,和普通型母函数一样暴力展开就能得到答案了
继续上面的例子,将展开式展开即得:
1 + 3 x + 9 2 x 2 + 25 6 3 + 31 12 x 4 + 13 12 x 5 + 7 24 x 6 + 1 24 x 7 1+3x+\frac{9}{2}x^2+\frac{25}{6}^3+\frac{31}{12}x^4+\frac{13}{12}x^5+\frac{7}{24}x^6+\frac{1}{24}x^7 1+3x+29x2+6253+1231x4+1213x5+247x6+241x7
如果我们要求从上述物品中选取r个进行排列,只要找到指数为r的项,再将其系数乘以r的阶乘,原因可见上面证明过程的链接
对于指数型母函数来说,它的每一项的系数都是 a n n ! \frac{a_n}{n!} n!an,而其中真正有用的是 a n a_n an,这与用普通型母函数解决多重集组合问题单纯取系数不同。
4.模板
代码都有注释,需要注意的是结尾的输出要用%.0f,用%.0lf会输出0或-0我也不知道,用(int)强制转换也是不行的,因为会截断,而答案需要四舍五入(应该是精度问题造成的,不然答案本来就应该是整数)
#include<iostream>
#include<cstdio>
#include<string.h>
using namespace std;
int fact[15];
void fact_calculate(){//阶乘计算
fact[0]=fact[1]=1;
for(int i=2;i<=10;i++)
fact[i]=i*fact[i-1];
}
int main()
{
int n,m;
double c[15],temp[15]; //c数组存放系数
int num[15]; //存放第i种物品有几个
fact_calculate();
while(~scanf("%d%d",&n,&m)){
memset(c,0,sizeof(c));
for(int i=1;i<=n;i++)
scanf("%d",&num[i]);
for(int i=0;i<=num[1];i++) //c数组初始化第一个多项式的系数
c[i]=1.0/fact[i];
for(int i=2;i<=n;i++){ //i表示运算到第几个多项式
memset(temp,0,sizeof(temp));
for(int j=0;j<=m;j++) //循环到m项就可以,因为求的是m排列,后面的项计算了也没有意义
for(int k=0;k<=num[i]&&k+j<=m;k++)
temp[k+j]+=(1.0*c[j]/fact[k]);
for(int j=0;j<=m;j++)
c[j]=temp[j];
}
printf("%.0f\n",c[m]*fact[m]);
}
return 0;
}
5.泰勒展开式的应用
e x e^x ex的泰勒展开:
e x = 1 + x + x 2 2 ! + x 3 3 ! + ⋅ ⋅ ⋅ e^x=1+x+\frac{x^2}{2!}+\frac{x^3}{3!}+\cdot\cdot\cdot ex=1+x+2!x2+3!x3+⋅⋅⋅
可见其与我们构造的指数型母函数是恰好契合的
扩展:
e − x = 1 − x + x 2 2 ! − x 3 3 ! + ⋅ ⋅ ⋅ e^{-x}=1-x+\frac{x^2}{2!}-\frac{x^3}{3!}+\cdot\cdot\cdot e−x=1−x+2!x2−3!x3+⋅⋅⋅
则:
e x + e − x 2 = 1 + x 2 2 ! + x 4 4 ! + ⋅ ⋅ ⋅ \frac{e^x+e^{-x}}{2}=1+\frac{x^2}{2!}+\frac{x^4}{4!}+\cdot\cdot\cdot 2ex+e−x=1+2!x2+4!x4+⋅⋅⋅
e x − e − x 2 = 1 + x + x 3 3 ! + ⋅ ⋅ ⋅ \frac{e^x-e^{-x}}{2}=1+x+\frac{x^3}{3!}+\cdot\cdot\cdot 2ex−e−x=1+x+3!x3+⋅⋅⋅
具体应用:
可看红色病毒 这题
题解:点击跳转