HDU 1521 排列组合(指数型母函数)

传送门

Problem Description
有n种物品,并且知道每种物品的数量。要求从中选出m件物品的排列数。例如有两种物品A,B,并且数量都是1,从中选2件物品,则排列有”AB”,”BA”两种。

Input
每组输入数据有两行,第一行是二个数n,m(1<=m,n<=10),表示物品数,第二行有n个数,分别表示这n件物品的数量。

Output
对应每组数据输出排列数。(任何运算不会超出2^31的范围)

Sample Input
2 2
1 1

Sample Output
2

题目大意:
是中文的,没什么好说的。。。

解题思路:
这是一个典型的指数型的母函数,其实对于指数型的母函数,首先给出母函数的定义:
设{an}为序列则称

G(x)=n=0nanxn/n!

为序列 an 的指数型生成函数(母函数)
注意的是 指数型的母函数主要解决的问题是排列的问题与普通型的母函数还是有很大区别的,具体的样例模板就是:
1.假设有8个元素,其中a1重复3次,a2重复2次,a3重复3次。从中取r个组合,求其排列数。
HDU 1521 排列组合(指数型母函数)_第1张图片

2.就是解决什么多重集的r-排列数。
设 S = {n1*a1, n2*a2, … ,nk*ak}为多重集,则S的r-排列数的指数型母函数为:

G(x)=fn1(x)fn2(x)...fnk(x)

其中
fni(x)=1+x+x2/2!+...+xni/ni!

3.由1,2,3,4,组成的5位数中,要求 1 出现 不超过 2次,但不能不出现,2 出现不超过1 次,3 至多出现 3 次,4出现偶数次.求这样的 5 位数个数.
解:
G(x)=(x/1!+x2/x!)(1+x)(1+x+x2/2!+x3/3!)(1+x2/2!+x4/4!)=(x+5x2/2!+..+215x5/5!+...)

所以 这样的5位数个数是 215 个
4.红白蓝涂色 1*n的方格,要求偶数个位白色,问有多少方案.
解:
其实跟上一个差不多,

G(x)=(1+x2/2!+..)(1+x+x2/2!+..)2=1/2(ex+ex)e(2x)

然后最后求出来就是 an = (3^n+1)/2

然后说一下这个题就是一个裸的指数型的母函数,所以直接就是套模板就行了,基本上都是一样的。就是求阶乘的时候尽量使用小数求,这样是为了算数的时候方便。。。

My Code:

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
typedef long long LL;
const int MAXN = 15;
LL a[MAXN];
double c1[MAXN],c2[MAXN];
double jc(int m)
{
    double ret = 1.0;
    for(int i=2; i<=m; i++)
        ret *= i;
    return ret;
}
void Init()///初始化
{
    memset(c1, 0, sizeof(c1));
    memset(c2, 0, sizeof(c2));
}
int main()
{
    int n, m;
    while(cin>>n>>m)
    {
        Init();
        for(int i=0; i<n; i++)
            cin>>a[i];
        for(int i=0; i<=a[0]; i++)
            c1[i] = 1.0/jc(i);
        for(int i=1; i<n; i++)
        {
            for(int j=0; j<MAXN; j++)
            {
                for(int k=0; k<=a[i]&&(k+j<MAXN); k++)
                    c2[k+j] += c1[j]/jc(k);
            }
            for(int j=0; j<MAXN; j++)
            {
                c1[j] = c2[j];
                c2[j] = 0;
            }
        }
        printf("%.0lf\n", c1[m]*jc(m));
    }
    return 0;
}

你可能感兴趣的:(指数型母函数)