生成函数入门级内容

生成函数就是母函数。

说的俗一点,生成函数可以理解为多维的卷积:$c_k=\sum_{i_1+i_2+...+i_n=k} A_{j,i_1}

具体怎么理解呢?举个栗子:我们有1¥,2¥,3¥的无数张纸币,求有多少种组成x¥的方案。

我们设生成函数$f_1(x)=(1+x^1+x^2+x^3+...)$,$f_2(x)=(1+x^2+x^4+x^5+...)$,$f_3(x)=(1+x^3+x^6+x^9+...)$

将他们全部乘起来,得到:$(1+x^1+x^2+x^3+...)(1+x^2+x^4+x^5+...)(1+x^3+x^6+x^9+...)$。

那么有多少种组成x¥的方案就是幂次是x的项的系数。这很好理解。

 

具体来说:生成函数有很多种,常见的有

1.普通生成函数:$k_n(x)=x^n$

2.指数生成函数:   $k_n(x)=\frac{x^n}{n!}$

3.狄利克雷生成函数:  $k_n(x)=\frac{1}{n^x}$

 

由于是入门级内容,我们优先说明普通生成函数。

普通生成函数:

简单来说多项式的系数表示序列的元素。由于不关心x的数值,所以称x为自由元的形式幂级数。

对于这个多项式,既可以有限又可以无穷。

听起来它并什么卵用。但细发掘发现:如果一个序列有通项公式,那么它的普通生成函数的系数就是该通项公式。

那么是否可以通过求生成函数来得到一个数列的通项公式呢?可以!说的更明白一点,就是利用生成函数可以求乱七八糟递推公式的通项公式,比如著名的斐波那契数列。

在说斐波那契数列之前,我们先看看简单的例子:$\frac{1}{1-x}$的生成函数是:$f(x)=\sum_{i=0}^{+\infty} x^i$

即:$\frac{1}{1-x}=\sum_{i=0}^{+\infty} x^i$

这是怎么做到的呢?我们发现后面的是一个等比数列,根据等比数列通项公式。当$-1<x<1$时,$lim_{n→+∞}x^{n+1}=0$,由此得到。

推论:$\frac{1}{1-kx}=\sum_{i=0}^{+\infty} k^ix^i$。这个推论很重要,在阅读推理斐波那契通项公式时如果有什么不理解的请立刻将视线移到此处。

接下来我们用求简单的斐波那契数列通项公式来作为普通生成函数的小练习,如果认为前面的内容理解不错的可以自己先推一推,思想还是比较基础的。

解:

斐波那契数列:$f_i=f_{i-1}+f_{i-2}$

我们设生成函数$f(x)=1+1x+2x^2+3x^3+5x^4+8x^5$,可以发现,每项的系数就是斐波那契数列。

观察发现: $f(x)=1+1x+2x^2+3x^3+5x^4+8x^5+13x^6$

                   $xf(x)=$     $1x+1x^2+2x^3+3x^4+5x^5+8x^6$

      $x^2f(x)=$              $1x^2+1x^3+2x^4+3x^5+5x^6$

由于$f_i=f_{i-1}+f_{i-2}$,结合观察列出下列式子:$f(x)-xf(x)=x^2f(x)$。

将$f(x)$视为主元,我们得到:$f(x)=\frac{1}{1-x-x^2}$

显然仅仅如此我们并不知道f(x)的每一项的系数,但是通过观察可以发现一些有趣的事情,比如:将$\frac{1}{1-x-x^2}$往$\frac{1}{1-kx}$上靠的话,我们可以知道每一项的系数(想想之前讲过的内容),其中第i项的系数是$k^i$。

首先将$1-x-x^2$因式分解:得到$(1-Ax)(1-Bx)=1-x-x^2$。其中$A=\frac{1+\sqrt 5}{2}$,$B=\frac{1-\sqrt 5}{2}$

回忆高中知识裂项分解:$\frac{1}{n(n+k)}=\frac{1}{k}(\frac{1}{n}-\frac{1}{n+k})$

因为:$f(x)=\frac{x}{(1-Ax)(1-Bx)}$,其中$(1-Bx)=(1-Ax)+\sqrt 5 x$

所以$f(x)=\frac{x}{\sqrt 5 x}(\frac{1}{1-Ax}-\frac{1}{1-Bx})=\frac{1}{\sqrt 5}(\frac{1}{1-Ax}-\frac{1}{1-Bx})$

假设我们要求斐波那契数列的第n项,那么对于上面括号里的内容中第n项的系数就是$A^n-B^n$,而括号外的数是一个常数列

所以斐波那契的第n项的通项公式就是$\frac{1}{\sqrt 5}(A^n-B^n)=\frac{1}{\sqrt 5}((\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n)$

 

但是,你知道了斐波那契数列的通项公式毛用没有,因为5在模比如说1e9+7的意义下是没有二次剩余的。

这个时候我们要引入一种黑科技:扩域

想想FFT,我们单位负根正式形如(a+bi)的样子。i是复数域上特有的符号,$i^2=-1$。这个就可以理解成扩域的实例。

那么对于这个通项公式呢?我们定义自己的域,比如说我叫他神域,由神部和人部组成,形如$(a,b\sqrt 5)$。

对于这个神域,乘法就可以这么定义:$(a+b\sqrt 5)(c+d\sqrt 5)=(ac+5bd)+(ad+bc)\sqrt 5$。

而对于加法和减法,我们就和复数域一样就好了。容易看出,神域满足结合律和交换律。

既然满足上面两个“律”,那么快速幂显然适用于神域。那么$(\frac{1+\sqrt 5}{2})^n-(\frac{1-\sqrt 5}{2})^n$就可以很轻松的算出了。

但是有的人会说,不是上面式子算出来的答案要除$\sqrt 5$吗?正好我们神域的人部一定存在$\sqrt 5$。至于神部,显然在这个通项公式中等于0啦~(因为正好相减抵消了)

所以最终的答案就是人部的系数了。 理论时间复杂度是矩阵乘法的$\frac{1}{2}$。但是由于扩域冗杂的计算,实际耗时要高于矩阵乘法。

 

 

#include <iostream>
#include <cmath>
#define int long long
#define inc(i,a,b) for(register int i=a;i<=b;i++)
const int p=1e9+7;
using namespace std;
struct complex{
    long long x,y;
    complex (long long xx=0,long long yy=0){x=xx,y=yy;}
}a[200010],b[200010];
complex operator + (complex a,complex b){return complex((a.x+b.x)%p,(a.y+b.y)%p);}
complex operator - (complex a,complex b){return complex(((a.x-b.x)%p+p)%p,((a.y-b.y)%p+p)%p);}
complex operator * (complex a,complex b){return complex(((a.x*b.x%p+5*a.y%p*b.y%p)+p)%p,(a.x*b.y%p+a.y*b.x%p)%p);}
long long n;
long long KSM(long long a,long long b){
    long long res=1; while(b){
        if(b&1) res=res*a%p;
        a=a*a%p; b/=2;
    } return res%p;
}
complex speKSM(complex tmp,int b){
    complex res=complex(1,0);
    while(b){ if(b&1) res=res*tmp;
        tmp=tmp*tmp; b/=2;
    } return res;
}
signed main(){
    cin>>n;
    complex x=complex(500000004,500000004);
    complex y=complex(500000004,p-500000004);    
    x=speKSM(x,n); y=speKSM(y,n);
    complex ans=x-y; printf("%lld",ans.y);
}

 

posted @ 2020-06-24 15:41  神之右大臣  阅读(299)  评论(0编辑  收藏  举报