指数生成函数小练

介绍

对于一些很复杂/凑数的组合题目,我们用普通的生成函数,特别是那些涉及二项式系数的数列,这是因为ta有二项式定理的形式
现在针对排列问题,我们有“指数生成函数”这种东西,即对于一个无穷数列h,他的指数生成函数g(x)定义为
g(x)=infn=0xnn!=h1+h2x+h3x22!+... g ( x ) = ∑ n = 0 i n f x n n ! = h 1 + h 2 x + h 3 x 2 2 ! + . . .
然后一些套路图直接引用这个up的啦
指数生成函数小练_第1张图片
指数生成函数小练_第2张图片

T1

POJ3734 Blocks

题意

用红黄蓝绿给n个格子染色,要求红色和绿色必须是偶数个,求方案数。对10007取模。

思路

涉及到了排列问题,我们用指数型生成函数
其实套路跟普通的生成函数一样了,只不过列的初始柿子不一样了

(1+x22!+x44!...)2(1+x+x22!+x33!...)2=(ex+ex2)2e2x=e4x+2e2x+14 ( 1 + x 2 2 ! + x 4 4 ! . . . ) 2 ( 1 + x + x 2 2 ! + x 3 3 ! . . . ) 2 = ( e x + e − x 2 ) 2 e 2 x = e 4 x + 2 e 2 x + 1 4

我们知道 ex=1+x+x22!+x33!+...=infn=0xnn! e x = 1 + x + x 2 2 ! + x 3 3 ! + . . . = ∑ n = 0 i n f x n n !
那么 e4x=infn=0(4x)nn!=infn=04nxnn! e 4 x = ∑ n = 0 i n f ( 4 x ) n n ! = ∑ n = 0 i n f 4 n x n n !
继续化简原式
e4x+2e2x+14=14+n=0inf4n+2n+14xnn! e 4 x + 2 e 2 x + 1 4 = 1 4 + ∑ n = 0 i n f 4 n + 2 n + 1 4 x n n !

那么填n个格子依然是第n项的系数,即 4n+2n+14 4 n + 2 n + 1 4

代码

#include 
#define LL long long
using namespace std;
const int mod=10007;
LL ksm(LL a,int k)
{
    LL ans=1;
    for (;k;k>>=1,a=a*a%mod)
      if (k&1) ans=ans*a%mod;
    return ans;
}
int main()
{
    int T,n;scanf("%d",&T);
    LL inv=ksm(4,mod-2);
    while (T--)
    {
        scanf("%d",&n);
        printf("%d\n",(ksm(4,n)+ksm(2,n+1))%mod*inv%mod);
    }
}

T2

HDU1521 排列组合

思路

中文题?!
还是可以根据套路列出柿子

(1+x+x22!+x33!+...+xm1m1!)(1+x+x22!+x33!+...+xm2m2!)... ( 1 + x + x 2 2 ! + x 3 3 ! + . . . + x m 1 m 1 ! ) ( 1 + x + x 2 2 ! + x 3 3 ! + . . . + x m 2 m 2 ! ) . . .

依然是求第m项的系数,暴力展开求解
但是要记住,我们求的第m项的系数是
n=0infaxnn! ∑ n = 0 i n f a x n n !
中的a,所以答案要乘上mul[m]
a数组记得要清零

代码

#include 
#include 
#include 
using namespace std;
double mul[50],a[50],b[50];int v[15];
int main()
{
    mul[0]=1;for (int i=1;i<=10;i++) mul[i]=mul[i-1]*i;
    int n,m;
    while (scanf("%d%d",&n,&m)!=EOF)
    {
        for (int i=1;i<=n;i++) scanf("%d",&v[i]),v[i]=min(v[i],m);
        memset(b,0,sizeof(b));memset(a,0,sizeof(a));
        for (int i=0;i<=v[1];i++) a[i]=1.0/mul[i];
        for (int i=2;i<=n;i++)
        {
            for (int j=0;j<=m;j++)
              for (int k=0;k<=v[i];k++) b[j+k]+=a[j]*1.0/mul[k];
            for (int j=0;j<=m;j++) a[j]=b[j],b[j]=0;
        }
        printf("%.0lf\n",a[m]*mul[m]);
    }
}

你可能感兴趣的:(生成函数)