生成函数

组合数学里面的生成函数是一个非常有力的工具,主要用在计数,以及求解递推公式上面。这里简要总结一下《组合数学》Brualdi中的生成函数的应用

组合型生成函数

考虑这样一个问题求解
e1+e2+...+ek=n
的非负整数解的总数
单独考虑选择 e1 的种类数

11x=i=0xi

xi 的系数表示选择 e1=i 的种类数
同理对于任意的 ei

11x=i=0xi

那么 e1+e2+...+ek=n 的种类数就等于

(i=0xi)...(i=0xi)
=(11x)k
=(k+n1n)xn

其中 xn 的系数就表示的是 e1+e2+...+ek=n
的非负整数解的总数。
你也可以不用这种方式而用纯理论的方式来推出这个方程的非负整数解总数为

(k+n1n)

这种生成函数多用在组合计数问题上,让我们拓展一下解决下面这个问题
3e1+4e2+2e3=n
的非负整数解

f(x)=(x3i)x4ix2i

因为每一个 e1 贡献的是3个值!
同理如果对 ei 有限制的话就需要限制x的最高次幂

模板题

hdu 2082 找单词
这就是生成函数最简单的应用,主要是对多项式的编码可能会有点困难这里给出代码,本人代码很挫,请大牛指正

#include 
#include
#include
#include
#include
#include
#include
#define Debug(x) cout<<(x)<
#define fi first
#define se second
using namespace std;
typedef long long LL;
typedef pair<int,int > PII;
typedef map<int,int >::iterator MIT;

const int maxn = 55;

LL a[maxn],b[maxn],c[maxn];

int main()
{
    //freopen("H:\\c++\\file\\stdin.txt","r",stdin);
    int T;
    scanf("%d",&T);
    while(T--)
    {
        memset(b,0,sizeof(b));
        memset(c,0,sizeof(c));
        b[0] = 1;
        for(int i = 1 ; i<= 26 ; ++i)
        {
            memset(a,0,sizeof(a));
            LL x;
            scanf("%I64d",&x);
            a[0] = 1;
            for(int j = 0 ; j<=50 && j<=i*x ; j+=i)
            {
                a[j] = 1;
            }
           // for(int i=0 ; i<=50 ; ++i)
               // Debug(a[i]);
            for(int j = 0 ; j<=50  ; j++)
            {
                for(int k = 0 ; k<=50 &&k<=i*x && j+k <=50; k++)
                {
                    c[j+k]+= b[j]*a[k];
                }
            }
            memcpy(b,c,sizeof(c));
            memset(c,0,sizeof(c));
        }
        LL ans = 0;
        for(int i =1 ; i<=50 ; ++i)
            ans+=b[i];
        printf("%I64d\n",ans);
    }

    return 0;
}

指数型生成函数

多重集合 {n1a1,...,nkak} n 排列数,我们知道当 n 恰好等于 ni 的时候,这个数是 n!n1!...nk! ,那么他不等于他的时候呢

fni(x)=nii=0xii!

ge(x)=ki=1fni(x)

的Taylar 级数展开项 xnn! 的系数就是解的个数,我们展开就发现
解为
n!m1!..mk! 其中 mi=n 的所有整数解

这种生成函数主要解决排列问题

例子

poj 3734 Blocks
n 种砖,用4种颜色来着色,其中红色与蓝色为偶数个问着色方法数
仿照前面的方式我们不难发现对次数做一些限制就的到偶数着色的生成函数

ge(x)=i=0x2i(2i)!=ex+ex2

所以最后的生成函数就是

(ex+ex2)2e2x=14+(4n1+2n1)xnn!

所以答案就是

(4n1+2n1)

例题

poj 1322 Chocolate

你可能感兴趣的:(算法理论)