zoukankan      html  css  js  c++  java
  • 【讲稿】8.13杂题选讲 | 【学习笔记】普通生成函数 | 【题解】 luogu P2000 拯救世界

    • UPD on 8.11:纠正了关于斐波那契数列待定系数法的方程
    • UPD on 8.12:纠正了关于收敛半径的描述

    又要杂题选讲了qwq,由于本人太菜而且暑假集训后完全在搞whk啥题都没刷,于是只能讲模板了/kk

    一.啥是生成函数

    生成函数是一个晾衣绳,我们把一系列的数字挂在上面以供显示。——《(Generating) (Funtionology)

    上面那句话是什么意思,我们姑且不谈反正我也不知道是什么意思。我们从中大概可以感受到,生成函数是一种处理序列问题的工具,那么我们接下来再看这本书里的另一端话:

    假设我们有一个问题,答案是一系列的数字({ a_i }),我们想知道这个序列是什么。我们会得到什么样的答案呢?
    一个简单的公式将是最好的。如果我们发现对于每个 (n=0,1,2,…,a_n=n^2+3),那么毫无疑问我们已经“回答”了这个问题。
    但是如果没有简单的公式来计算未知序列?毕竟,有些序列是复杂的——举个令人毛骨悚然的例子,假设未知序列是({ 2,3,5,7,11,13,17,19,…,}) 其中 (a_n) 是第 (n) 个素数。那么,它指望得到任何一种简单的公式都是不合理的。
    生成函数给你提供另外一种解决这种问题的有力方式,虽然给序列成员一个简单的公式是不可能的,但是我们可以给出一个关于幂级数和的简单公式,它的系数就是我们要找的序列。——《(Generating) (Funtionology)

    好的,我们现在已经知道生成函数是用来干什么的了,接下来我们直接切入正题——

    二.普通生成函数 (opsgf) 的定义

    我们定义一个序列 ({ a_i }) 的普通生成函数为

    [F(x)=sumlimits_{k}{a_kx^k} ]

    ({ a_i }) 既可以是有穷序列,也可以是无穷序列,下面有一些常见的例子:

    1. 序列 ({1,2,3}) 的普通生成函数是 (F(x)=1+2x+3x^2)
    2. 序列 ({1,1,...,1}) 的普通生成函数是 (sumlimits_{k}{x^k})

    换句话说,如果序列 ({ a_i }) 有通项公式,那么他的生成函数的系数就应该是他的通项公式。
    知道了上面的东西并没有任何用处,我们不知道怎么应用它,而他的用法——求封闭形式,就要从我们提到过的序列 ({1,1,...,1}) 的普通生成函数

    [F(x)=sumlimits_{k}{x^k} ]

    讲起——

    三.普通生成函数的封闭形式

    大家可能在很多地方都见到过这样一个定理:

    [sumlimits_{k geq 0}{x^k}=frac{1}{1-x} ]

    这个定理的正确性看起来一点也不显然嘛,那我们换个角度看问题:
    有个非常显然的性质:

    [F(x)x+1=F(x) ]

    其实他就相当于把 (F(x)) 整体向右平移一位,然后在前面补 (1) ,其实这种方法类似扰动法的解方程,我们把上面的那个方程解了,就得到了这个定理

    [sumlimits_{k geq 0}{x^k}=frac{1}{1-x} ]

    这玩意的收敛半径是 (|x| < 1)
    如果你理解了上面的过程,那么恭喜你,你已经初步掌握了生成函数的处理技巧之一——求封闭形式。
    我们把上面的过程称为求封闭形式,把从 (frac{1}{1-x}) 推回原来的函数称为级数展开,而且显然这两个东西是可以互推的。
    好的,那么在我们初步学会了普通生成函数之后,我们来看一个应用。

    四.利用普通生成函数解斐波那契数列的通项问题

    • 问题:定义斐波那契数列 (f_i=f_{i-1}+f_{i-2},f_1=f_2=1),求 ({ f_i }) 通项。

    解:首先设 ({ f_i }) 的普通生成函数为

    [F(x)=sumlimits_{k geq 1}{f_kx^k} ]

    这个套路在《(Generating) (Funtionology)》里面被称为 (Snake) (Oil) (Method),继续按套路,设

    [G(x)=sumlimits_{k geq 3}{f_kx^k}=F(x)-x-x^2 ]

    其实这个套路跟我们上面求 (sumlimits_{k geq 0}{x^k}) 的作用是一样的,都是通过发现 (F(x)) 的性质从而解出他的封闭形式,那么有:

    [G(x)=sumlimits_{k geq 3}{f_kx^k}=sumlimits_{k geq 3}{(f_{k-1}+f_{k-2})x^k}=xsumlimits_{k geq 2}{f_kx^k}+x^2 sumlimits_{k geq 1}{f_kx^k}=x(F(x)-x)+x^2F(x) ]

    结合 (G(x)=F(x)-x-x^2),移项解得:

    [F(x)=frac{x}{1-x-x^2} ]

    这就是斐波那契数列的生成函数。
    到了这一步,我们将它级数展开,按套路设:

    [frac{x}{1-x-x^2}=frac{x}{(1-x·x_1)(1-x·x_2)}=frac{A}{1-x·x_1}+frac{B}{1-x·x_2} ]

    可解得 (x_1=frac{1 + sqrt 5}{2},x_2=frac{1 - sqrt 5}{2}),整理上式有:

    • (frac{x}{1-x·x_2}=A+frac{1-x·x_1}{1-x·x_2}B)
    • (frac{x}{1-x·x_1}=B+frac{1-x·x_2}{1-x·x_1}A)

    这个是一个非常经典的 (trick),推很多别的生成函数的式子的时候都可以这样子做,在这两个式子中分别令 (x·x_1=1,x·x_2=1),最后可解出:

    [A=frac{1}{sqrt 5},B=-frac{1}{sqrt 5} ]

    (F(x)=frac{A}{1-x·x_1}+frac{B}{1-x·x_2})级数展开:

    [F(x)=A(sumlimits_{k geq 1}{(x·x_1)^k})+B(sumlimits_{k geq 1}{(x·x_2)^k}) ]

    (A,B,x_1,x_2) 全部代入,最后有:

    [F(x)=sumlimits_{k geq 1}[frac{1}{sqrt 5}(frac{1 + sqrt 5}{2})^k-frac{1}{sqrt 5}(frac{1 - sqrt 5}{2})^k]x^k ]

    于是有斐波那契数列的通项公式:

    [f_n=[x^n]F(n)=frac{1}{sqrt 5}(frac{1 + sqrt 5}{2})^n-frac{1}{sqrt 5}(frac{1 - sqrt 5}{2})^n ]

    好的,看来我们现在已经成功应用普通生成函数解决了一些有趣的问题了,下面我们对上面的思想/套路作一些总结:

    1. 首先,我们要求序列 ({ a_i }) 的通项公式,那么就把它的普通生成函数 (F(x)) 设出来
    2. 求出 (F(x)) 的封闭形式
    3. 再把 (F(x)) 的封闭形式展开,取系数,就得到了答案

    好哇,这就是我们今天杂题选讲的全部内容了,大家再见!
    好吧,既然是杂题选讲,还是得讲点题的。

    五.例题:LG P2000 拯救世界

    我们将题目中的限制所代表的生成函数列出来(具体我们讲题的时候解释):

    [egin{array}{l} 1+x^{6}+x^{12}+cdots=frac{1}{1-x^{6}} \ 1+x+x^{2}+cdots+x^{9}=frac{1-x^{10}}{1-x} \ 1+x+x^{2}+cdots+x^{5}=frac{1-x^{6}}{1-x} \ 1+x^{4}+x^{8}+cdots=frac{1}{1-x^{4}} \ 1+x+x^{2}+cdots+x^{7}=frac{1-x^{8}}{1-x} \ 1+x^{2}+x^{4}+cdots=frac{1}{1-x^{2}} \ 1+x=frac{1-x^{2}}{1-x} \ 1+x^{8}+x^{16}+cdots=frac{1}{1-x^{8}} \ 1+x^{10}+x^{20}+cdots=frac{1}{1-x^{10}} \ 1+x+x^{2}+x^{3}=frac{1-x^{4}}{1-x} end{array}]

    然后把他们全部乘起来,得到

    [frac{1}{(1-x)^{5}} ]

    有一个这样子的结论(广义二项式定理):

    [frac{1}{(1-x)^{n}}=sum_{i=0}^{infty} {{n+i-1} choose {i}} x^{i} ]

    那么我们上面得到的式子就是 (n=5) 的情况,所以:

    [frac{1}{(1-x)^{5}}=sum_{i=0}^{infty} {{i+4} choose {i}} x^{i} ]

    所以答案就是 ({n+4} choose {n}),这题做完了。

    凑合着放一下代码

    n=int(input())
    print((n+1)*(n+2)*(n+3)*(n+4)//24)
    

    你问我为啥写 (Python)?
    是不可能写高精度的,这辈子都不可能再写高精度的
    UPD. (Py)被卡了,所以还是老实写高精压位或者 (ntt) 优化吧/kk

    完结撒花!!!

  • 相关阅读:
    【Spring学习随笔】1. Spring的体系结构
    MySQL图形化安装相关总结(含软件分享)
    Spring Bean 基于注解的装配
    vue的三种图片引入方式
    wx.navigateTo({ url: '', }) 跳转无效问题
    JDK环境变量配置
    如何实现Vue底部按钮点击加载更多
    Java Web学习路线
    百度地图循环添加标注,并循环为鼠标悬停标注时信息窗口问题解决
    mvc jquery 修改 viewbag
  • 原文地址:https://www.cnblogs.com/lgj-lgj/p/13466909.html
Copyright © 2011-2022 走看看