n个元素组成的多重集,其中a1重复了n1次,a2重复了n2次,…,ak重复了nk次,若n=n1+n2+…+nk,从n个元素中取m个排列,求不同的排列数。
这种问题涉及到指数型母函数。
来看这道题~
题目大意
分别给定n个物品的数目,从中选m件的排列有多少个。
解题思路
指数型母函数,也叫做形式幂级数,即
以前讨论的母函数和指数母函数的差别,就在于前者直接用an作幂级数的系数,而后者则是用作为幂级数的系数,且真正有意义的就是an.
总的说来,指数型母函数可以说是普通母函数的衍生,要注意的是两者间的区别,一个是系数,另一个是指数的变化。
好了,有了一定的母函数基础,加上指数型母函数的知识,就可以求这道题了,注意要用到double数组啦,考虑浮点数精度误差等问题。
1.浮点数精度误差问题
2.浮点型double强制转换为整形int值,注意四舍五入,(int)(double+0.5)
3.注意32-bit整形最大能存储13!,还好题目只要求到10!
参考代码+部分注释
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <map>
#include <vector>
#include <cstring>
#include <cmath>
#define eps 1e-8
using namespace std;
typedef long long ll;
const int maxn = 1e2+10;
int n,m,fac[15],a[15];
double c1[maxn],c2[maxn];
void init() //初始化,数组fac[n]存储n!值
{
fac[0]=1;
for(int i=1;i<=12;i++)
fac[i]=fac[i-1]*i;
return;
}
int solve()//返回(ans/m!)*x^m系数中的ans
{
memset(c1,0,sizeof(c1));//c1用于存储最终结果
memset(c2,0,sizeof(c2));//c2用于保留中间结果
for(int i=0;i<=a[1];i++) c1[i]=1.0/fac[i];//第一个表达式初始化1+(1/1!)*x+(1/2!)*x^2+…
for(int i=2;i<=n;i++){ //剩下n-1个表达式
for(int j=0;j<=m;j++)//遍历前一个表达式的指数,找到对应系数非0的数
if(fabs(c1[j])>eps){ //要么不要这一行,要么注意浮点数精度误差
for(int k=0;k+j<=m&&k<=a[i];k++)//后一表达式遍历,注意与普通母函数处理的不同
c2[j+k]+=c1[j]/fac[k]; //系数处理,注意不同
}
memcpy(c1,c2,sizeof(c2));
memset(c2,0,sizeof(c2));
}
double ans=c1[m]*fac[m];
return (int)(ans+0.5); //浮点型强制转化为整形时+0.5!!!!!
}
int main()
{
// freopen("input.txt","r",stdin);
init(); //初始化,数组fac[n]存储n!值
while(cin>>n>>m){
for(int i=1;i<=n;i++) cin>>a[i];
cout<<solve()<<endl;
}
return 0;
}