ZROI 暑期高端峰会 A班 Day4 生成函数
一般生成函数
很普及组,不讲了
生成函数是一种形式幂级数,也就是我们只关心系数,不关心未知数具体的值。
比如 \(\sum\limits_{i\ge 0}x^i=\frac{1}{1-x}\)。虽然只有 \(0<x<1\) 时才是成立的,但是我们不管。
???
4 种东西,红黄蓝绿,都有无限个。现要求选出 \(n\) 个,要求红的偶数个,黄的 \(5\) 的倍数个,蓝的最多四个,绿的最多一个。问方案数。
生成函数瞎推一下,答案的生成函数 \(\frac{1}{(1-x)^2}\)。
组合意义理解一下,第 \(n\) 项系数是 \(\binom{n+2-1}{2-1}=n+1\)。答案就是 \(n+1\)。
指数型生成函数
还是很普及组,不讲了
指数型生成函数就是 \(\sum\limits_{i\ge 0}a_i\frac{x^i}{i!}\)。如果把两个指数型生成函数卷起来,就乘出来了组合数。
循环卷积
好像不怎么记得了……回去补一补。
(好的补完了)
考虑 \(A(x)=\sum\limits_{i=0}^{n-1}x^ia_i,B(x)=\sum\limits_{i=0}^{n-1}x^ib_i\),如何求出它们的循环卷积 \(C(x)\)?
还是考虑点值变换后:
\[C(\omega_{n}^k)=\sum\limits_{i=0}^{n-1}\omega_n^{ik}\sum\limits_{j=0}^{n-1}a_jb_{i-j\bmod n}\]
\[C(\omega_{n}^k)=\sum\limits_{i=0}^{n-1}\sum\limits_{j=0}^{n-1}\omega_n^{(i+j)k}a_ib_j\]
\[C(\omega_{n}^k)=(\sum\limits_{i=0}^{n-1}\omega_n^{ik}a_i)(\sum\limits_{j=0}^{n-1}\omega_n^{jk}b_j)\]
\[C(\omega_{n}^k)=A(\omega_{n}^{k})B(\omega_{n}^k)\]
一般直接暴力求值插值可以 \(O(n^2)\)。比起纯暴力卷积的优点在不用频繁变换,比如快速幂就可以做到 \(O(n^2+n\log k)\) 而不是 \(O(n^2\log k)\)。
对于一些比较特殊的 \(n\) 和模数可以质因子分解,类似普通 FFT 每次除以 2 分治,这里对任意一个质因子分解即可。([CTSC2010]性能优化)
还有二维循环卷积……回去补一补。
还有,还有……
???
\(n\) 点 \(m\) 边的有向图,每条边边权是二元组 \((a_i,b_i)\)。你身上有一个二元组 \((a,b)\),初始是 \((0,0)\)。每过一条边,二元组会变成 \(((a+a_i)\bmod n,(b+b_i)\bmod(n-1))\),另外给定一个 \(k\),对于每个点 \(i\) 和二元组 \((x,y)\),问从 \(i\) 开始走恰好 \(k\) 条边回到 \(i\),且二元组变成 \((x,y)\) 的方案数。答案对 \(1163962801\) 取模。
\(n\le 22,m\le 10000,k\le 10^9\)
把 \(n\times (n-1)\) 的矩阵作为转移矩阵的元素,乘法定义为二维循环卷积。时间复杂度 \(O(n^7\log k)\)。
既然是二维循环卷积,可以把每个矩阵 DFT,卷积后再 IDFT,复杂度就是 \(O(n^6+n^5\log k)\)。
模数不太友好,但是也有特殊之处,也可以瞎搞。
(考虑 \(998244353\) 能作为 NTT 模数的原因:\(998244353=2^{23}\times 19+1\),而原根——模意义下的单位根——我们要用到的次方是 \(g^{\frac{p-1}{d}}(d|n)\)(因为我们每次分治是分成两份,所以我们要把 \(n\) 变成 \(2\) 的次幂),所以如果 \(p-1\) 中 \(2\) 的个数不多就挂了。那么每次分治我们可以不是分成两份。对于这个模数,发现……#^$&!(#^(&@,所以就可以了。)
某个 TC Hard
\(n\) 次多项式 \(P(x)\),满足 \([x^i]P(x)=[x^{n-i}]P(x)\),也就是对称的。现在你知道 \(P^2(x)\) 在 \(\bmod x^{n+1}\) 意义下循环卷积的值,求 \(P(x)\)。
\(n\le 40\)。
考虑 \(P(\omega_n^k)=\sum\limits_{i=0}^{n-1}\omega_n^{ik}P_i\) 和 \(P(\omega_n^{n-k})=\sum\limits_{i=0}^{n-1}\omega_n^{i(n-k)}P_i=\sum\limits_{i=0}^{n-1}\omega_n^{ik}P_{n-i}\),实际上就是一个东西。
现在你知道每个 \(P^2(\omega_{n}^{k})\),也就能求出 \(P(\omega_n^k)\),注意要保持 \(P(\omega_n^k)=P(\omega_n^{n-k})\)。也就能插值回去。(好像是吧?)
???
\(m\) 个点的图,图中任意一条从 \(s\) 到 \(t\) 长度为 \(k\) 的倍数的路径会对答案产生 \(\binom{n}{len}\) 的贡献。答案对 \(P\) 取模。
路径不一定是简单路径。
\(m\le 10,k\le 1000,P\equiv 1\pmod k,n\le 10^{18}\)
首先发现这个贡献式很鬼畜,考虑换掉。
对每个点都连个自环。那么本来长度为 \(len\) 的路径,现在就变成了一定要走 \(n\) 个时刻,其中选 \(len\) 个时刻干正事,剩下的碌碌无为。
直接矩阵快速幂 \(O(k^2m^3\log n)\),不行。
发现 \(P\equiv 1\pmod k\),所以可以用一个 \(k\) 次单位根来 DFT,模数也很好。
复杂度 \(O(km^3\log n+k^2)\)。
Polya 定理
首先有 Burnside 引理:
然后有 Polya 定理:
(啥玩意来着?先去补一补)
生成函数可以和 Polya 定理合在一起。具体?咕了。
泰勒展开
把 \(F(x)\) 在 \(x_0\) 处展开,有:
\[F(x)=\sum\limits_{i\ge 0}\frac{(x-x_0)^iF^{(i)}(x_0)}{i!}\],其中 \(F^{(i)}\) 表示将 \(F\) 求导 \(i\) 次。
牛顿迭代
给定函数 \(G(x)\),求多项式 \(G(F(x))\equiv 0\pmod {x^n}\)。
考虑倍增,假如我们已经求出了 \(G(F_0(x))\equiv 0\pmod{x^{\lceil\frac{n}{2}\rceil}}\)。
做泰勒展开有:
\[G(F(x))=G(F_0(x))+\sum\limits_{i\ge 1}\frac{(F(x)-F_0(x))^iG^{(i)}(F_0(x))}{i!}\]
不难发现
\[(F(x)-F_0(x))^2\equiv 0\pmod{x^{2\lceil\frac{n}{2}\rceil}}\]
所以
\[0\equiv G(F(x))\equiv G(F_0(x))+(F(x)-F_0(x))G'(F_0(x))\pmod{x^n}\]
\[F(x)\equiv F_0(x)-\frac{G(F_0(x))}{G'(F_0(x))}\pmod {x^n}\]
多项式求逆
可以用牛迭推。
然而倍增也可以。
而且写多了都能记住了。
多项式除法
反转系数就行了。
也写过很多次,也记住了。
多项式 ln
导一下积一下就好了。
跟数没有区别。
注意的是常数项为 \(0\) 时才有意义。
多项式 exp
用牛迭推一下就好了。
注意的是常数项为 \(1\) 时才有意义。
其实写多了也能记住了。
多项式多点求值
给定 \(n\) 次多项式 \(P\) 和 \(m\) 个点 \(x_i\) 求所有 \(P(x_i)\)。
考虑分治,分成左右两半,对于左右分别求两个多项式 \(A_l(x)=\prod\limits_{i\in left}(x-x_i),A_r(x)=\prod\limits_{i\in right}(x-x_i)\)。
以左边的点为例,对于左边的点都有 \(A_l(x_i)=0\)。设 \(F(x)\bmod A_l(x)=R_l(x)\),那么有 \(F(x)=R_l(x)\)。直接分治即可。
如何求每个 \(A(x)\)?可以做另一次分治。总复杂度 \(O(n\log^2 n)\)(假设 \(n,m\) 同阶)。
多项式快速插值
就是给 \(n+1\) 个点和点值,要插值。
考虑拉格朗日插值。
分治,令 \(m=\lfloor\frac{n}{2}\rfloor,y_i=\frac{F(x_i)}{\prod\limits_{j\ne i}(x_i-x_j)}\)。
那么 \(F(x)=\sum\limits_{i=0}^ny_i\prod\limits_{j\ne i}(x-x_j)\)。
\[F(x)=\sum\limits_{i=0}^my_i\prod\limits_{j=0,j\ne i}^m(x-x_j)\prod\limits_{j=m+1}^n(x-x_j)+\sum\limits_{i=m+1}^ny_i\prod\limits_{j=0}^m(x-x_j)\prod\limits_{j=m+1,j\ne i}^n(x-x_j)\]
\[F(x)=\prod\limits_{j=m+1}^n(x-x_j)\sum\limits_{i=0}^my_i\prod\limits_{j=0,j\ne i}^m(x-x_j)+\prod\limits_{j=0}^m(x-x_j)\sum\limits_{i=m+1}^ny_i\prod\limits_{j=m+1,j\ne i}^n(x-x_j)\]
这里可以分治。
首先前面每个多项式先来一次分治求,\(O(n\log^2n)\)。
当分治到只有一个点的时候,就要用上 \(y_i\) 了。如何求 \(y_i\)?
\(F(x_i)\) 已知,所以让 \(z_i=\prod\limits_{j\ne i}(x_i-x_j)\)。
令 \(G(x)=\prod\limits_{i=0}^n(x-x_i)\),所以 \(z_i=\frac{G(x)}{x-x_i}\)。
根据洛必达法则,上下求个导,\(z_i=G'(x_i)\)。
所以 \(y_i=\frac{F(x_i)}{G'(x_i)}\)。
\(G(x)\) 在前面的分治中已经求过,求导后弄个多点求值,可以全部求出。
总复杂度 \(O(n\log^2n)\)。
分拆数
之前讲过了。
设 \(F(x)\) 为答案的生成函数。
\[F(x)=(1+x+x^2+\dots)(1+x^2+x^4+\dots)\dots\]
\(F(x)=\prod\limits_{i\ge 1}\frac{1}{1-x^i}\)
\[\ln F(x)=-\sum\limits_{i\ge 1}\ln(1-x^i)\]
\[\ln F(x)=\sum\limits_{i\ge 1}\sum\limits_{j\ge 1}\frac{x^{ij}}{j}\]
\[\ln F(x)=\sum\limits_{i\ge 1}x^i\sum\limits_{j|i}\frac{1}{j}\]
\(O(n\log n)\) 预处理,\(O(n\log n)\) exp 回去。复杂度 \(O(n\log n)\)。
还有五边形数的做法。
不知道为什么,但是就是可得 \(f_i=f_{i-p_1}+f_{i-p_{-1}}-f_{i-p_2}-f_{i-p_{-2}}+f_{i-p_3}+f_{i-p_{-3}}-\dots\)。
其中 \(p_i\) 是第 \(i\) 个五边形数,满足 \(p_i=\frac{3i^2-i}{2}\)。
直接做是 \(O(n\sqrt{n})\)。写成生成函数的形式,发现可以多项式求逆,\(O(n\log n)\),常数小很多。
cxk
\(n\) 个数 \(a_i\)。要选取一组 \(x_i\) 使得 \(\sum x_i=1\),要求存在一个 \(b\) 使得对于任意正整数 \(k\) 有 \(\sum x_ia_i^k=b^k\)。
\(x_i\) 不一定要在 \([0,1]\)。
问每个 \(x_i\)。对 \(998244353\) 取模。
\(n\le 10^5\)。
转化为一个方程组。发现只需要 \(n\) 条就够了(\(\sum x_i=1\) 可以看成是 \(k=0\) 时)。
发现这就是个范德蒙德矩阵。行列式可以快速计算:\(\prod\limits_{i<j}(x_j-x_i)\)。
使用线性代数里的 Cramer 法则,\(x_i=\frac{\det(A_i)}{\det(A)}\)。
发现分子是个很熟悉的形式。对,就是 \(\prod\limits_{j\ne i}(x-x_j)\)。用上面快速插值的方法即可。
中间掉线,错过了一题
???
已知 \(f(x)=\prod\limits_{i=1}^n(1+a_ix),g(x)=\prod\limits_{i=1}^n(1+b_ix)\),已知 \(f(x),g(x)\),求 \(h(x)=\prod\limits_{i=1}^n\prod\limits_{j=1}^n(1+a_ib_jx)\) 的第 \(k\) 项。
\[\ln f(x)=\sum\limits_{i=1}^n\ln(1+a_ix)\]
好像瞎推一波就行了?看起来没什么技术含量。
淘汰赛
\(n\) 个人的序列,进行 \(m\) 次比赛,每次比赛把幸存者分成若干段,每段中选手编号连续且至少两个,比赛完之后每段中恰好一个人获胜。每轮比赛过后,对选手重新编号(离散化)。\(m\) 次比赛后恰好剩下一个人。问有多少种不同的比赛过程。
\(n\le 10^{18},m\le 15\)
\(m=1\) 时生成函数是 \(F_1(x)=\frac{x^2}{1-x}\)。
\(m>1\) 时 \(F_m(x)=\frac{F_{m-1}(x)^2}{1-F_{m-1}(x)}\)。
设 \(F_m(x)=\frac{f_m(x)}{g_m(x)}=\frac{F_{m-1}(x)^2}{1-F_{m-1}(x)}\),大力推一波有 \(f_{m}(x)=f_{m-1}(x)^2=x^{2^m},g_m(x)=g_{m-1}(x)(g_{m-1}(x)-f_{m-1}(x))\)。
要求就是 \([x^n]\frac{x^{2^m}}{g_m(x)}\pmod {x^{n+1}}\)。
至于底下这东西的逆怎么求?要求的次数很高,不能简单求。但是发现可以通过前 \(n-1\) 项推出第 \(n\) 项。用的是一个 \(2^m\) 阶的递推公式。
\(O(2^mm\log n)\)。
最新文章
- JSPatch 使用
- UIView的几个layout方法
- 虚拟机锁定文件失败,开启模块snapshot失败解决办法
- PHP遍历目录四种方法
- 第五章 与众不同的this
- [Ogre][地形]OgreTerrain分析以及使用
- Netsharp快速入门(之8) 基础档案(工作区2 设置商品主列表、规格细列表、商品表单、查询)
- linux下mysql修改数据库账户root密码
- Java下载Servlet Demo
- rsync同步目录及同步文件
- [SQL]透過redgate SQL Monitor 來找出 ASYNC_NETWORK_IO 問題
- vue2.0 关于Vue实例的生命周期
- Android NDK开发三:java和C\C++交互
- add, subtract, multiply, divide
- 捕获数据中的某个序列---verilog
- 蓝牙SDP协议概述
- js -- sort() 使用排序函数
- 23.HashMap
- [转]使用@Test 也可以从spring容器中获取依赖注入
- C# LINQ to XML示例
热门文章
- How to get the free disk space in PostgreSQL (PostgreSQL获取磁盘空间)
- Javascript 日历插件
- 记录RFID操作错误
- mvc返回json数据
- maven 镜像仓库 setting.xml修改 &; 手动导入的包如何加到maven里面
- 【前端_React】npm常用命令
- 利用 FluentScheduler 启动定时器计划任务
- elastalert基本配置说明
- 使用PSCI机制的SMP启动分析
- wordpress迁移后登陆时出现Forbidden You don’t have permission to access /wp-login.php on this server