指数型母函数:hdu 1521 排列组合

n个元素组成的多重集,其中a1重复了n1次,a2重复了n2次,…,ak重复了nk次,若n=n1+n2+…+nk,从n个元素中取m个排列,求不同的排列数。

这种问题涉及到指数型母函数。

来看这道题~

题目大意

分别给定n个物品的数目,从中选m件的排列有多少个。

解题思路

指数型母函数,也叫做形式幂级数,即

这里写图片描述

以前讨论的母函数和指数母函数的差别,就在于前者直接用an作幂级数的系数,而后者则是用这里写图片描述作为幂级数的系数,且真正有意义的就是an.

这里写图片描述

总的说来,指数型母函数可以说是普通母函数的衍生,要注意的是两者间的区别,一个是系数,另一个是指数的变化。

好了,有了一定的母函数基础,加上指数型母函数的知识,就可以求这道题了,注意要用到double数组啦,考虑浮点数精度误差等问题。

1.浮点数精度误差问题

http://blog.csdn.net/u012717411/article/details/43638847

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;
}

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值