• 指数型母函数


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

    ————选自

    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
    ",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();
            }
        }
    }
  • 相关阅读:
    P1169 [ZJOI2007]棋盘制作
    P4147 玉蟾宫
    P1387 最大正方形
    动态规划之悬线法
    P2330 [SCOI2005]繁忙的都市
    最小生成树
    P2936 [USACO09JAN]全流Total Flow
    Python开发之规范化目录
    python模块知识四 包和logging日志
    python模块知识三 hashlib 加密模块、collections、re模块
  • 原文地址:https://www.cnblogs.com/chenhuan001/p/3209438.html
Copyright © 2020-2023  润新知