指数型母函数

母函数分:普通型母函数指数型母函数

————选自

Tanky Woo

普通型母函数主要是来求组合的方案数,而指数型母函数是求多重排列数。

关于普通型母函数的讲解,以前写过:

http://www.wutianqi.com/?p=596

而指数型母函数主要是关于排列组合方面的问题。

分别看两个比较典型的问题对比:

普通母函数问题:有红球两个,白球、黄球各一个,试求有多少种不同的组合方案。

指数型母函数问题:
假设有8个元素,其中a1重复3次,a2重复2次,a3重复3次。从中取r个组合,求其组合数。

下面是指数型母函数的定义

对于上面的问题“假设有8个元素,其中a1重复3次,a2重复2次,a3重复3次。从中取r个组合,求其组合数。”:

(感谢 3Dnn 同学指出,下图的 28/3! 应该改为 26/3!)

 

学习了,复习了,预习了,又复习了下母函数。

今天刷了两道指数型母函数的水题。

1. hdu 1521   http://acm.hdu.edu.cn/showproblem.php?pid=1521

题意很清楚,但是我发现如果利用以前所学的一点排列组合的基础,貌似这个很难找到排列组合公式。 用dp绝对可以,但是可能会稍有点复杂。如果你看过指数型母函数就知道这个很基础了。

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
#include <math.h>
#include <map>
#include <queue>
#include <sstream>
#include <iostream>
using namespace std;
#define INF 0x3fffffff
#define __int64 long long int
typedef __int64 LL;


int n,m;
int save[13];
int sum[13];
int tmp[13];
int g[13];

int main()
{
    //freopen("//home//chen//Desktop//ACM//in.text","r",stdin);
    //freopen("//home//chen//Desktop//ACM//out.text","w",stdout);
    save[0]=1;
    for(int i=1;i<=12;i++)
    {
        save[i]=save[i-1]*i;
    }

    while(scanf("%d%d",&n,&m)!=EOF)
    {
        for(int i=1;i<=n;i++)
            scanf("%d",g+i);
        memset(tmp,0,sizeof(tmp));
        memset(sum,0,sizeof(sum));
        for(int i=0;i<=g[1];i++)
        {
            sum[i]=1;
        }
        int cnt;
        for(int i=2;i<=n;i++)
        {
            for(int j=0;j<=m;j++)
                for(int k=0;k<=g[i];k++)
                {
                    if(j+k<=m)
                    {
                        cnt=save[j+k]/(save[j]*save[k]);
                        tmp[j+k] += cnt*sum[j];
                    }
                }
            for(int j=0;j<=m;j++)
            {
                sum[j]=tmp[j];
                tmp[j]=0;
            }
        }
        printf("%d\n",sum[m]);
    }
    return 0;
}

 

2. hdu 1261  http://acm.hdu.edu.cn/showproblem.php?pid=1261

这题和上面那题思路几乎一样,但是这题数据用long long 是存不下的,所以可以用java或大数。(我开始爱上java了)

可以用基础的像上题一样的解法写,模拟多项式相乘。 但是这题有个特殊的地方,就是会把所有的出现了的元素全部都选上, 于是在用指数型母函数将式子展开后,就会发现 x^n/n! (n为所有元素的和)这个项的系数为n!/(n1!*n2!*...*nk!). 这就可以看出母函数在优化方面往往有重大贡献。 这也是母函数的最重要的一种用法吧

附一份接近超时的模拟多项式相乘的java代码:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
import java.util.Scanner;
import java.math.BigInteger;

/**
 *
 * @author chen
 */
public class Main {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        // TODO code application logic here
        int n;
        Scanner in=new Scanner(System.in);
        n=in.nextInt();
        BigInteger[]save;
        save=new BigInteger[320];
        save[0]=BigInteger.valueOf(1); // 原来java每次定义数组都要这样做;先声明然后在申请空间
        for(int i=1;i<320;i++)
        {
            BigInteger tmp1=BigInteger.valueOf(i);
                save[i]=save[i-1].multiply(tmp1);
        }
        //for(int i=0;i<=26;i++)
               //System.out.println(sum[i]);
        while(n!=0)
        {
            BigInteger sum[];
            sum = new BigInteger[320];
            BigInteger tmp[];
            tmp = new BigInteger[320];
            int g[];
            g = new int[30];
            int num;
            num=0;
            for(int i=1;i<=n;i++)
            {
                g[i]=in.nextInt();
                num+=g[i];
            }
            for(int i=0;i<320;i++)
            {
                sum[i]=BigInteger.valueOf(0);
                tmp[i]=BigInteger.valueOf(0);
            }
            for(int i=0;i<=g[1];i++)
                sum[i]=BigInteger.valueOf(1);
            for(int i=2;i<=n;i++)
            {
                for(int j=0;j<=num;j++)
                    for(int k=0;k<=g[i];k++)
                    {
                        BigInteger tmp1;
                        if(j+k<=num)
                        {
                            tmp1=save[j+k].divide(save[j].multiply(save[k]));
                            tmp[j+k]=tmp[j+k].add( sum[j].multiply(tmp1) );
                        }
                    }
                for(int j=0;j<=num;j++)
                {
                    sum[j]=tmp[j];
                    tmp[j]=BigInteger.valueOf(0);
                }
            }
            System.out.println(sum[num]);
            n=in.nextInt();
        }
    }
}

 

 

 

posted @ 2013-07-23 21:28  chenhuan001  阅读(548)  评论(0编辑  收藏  举报