各式各样的小技巧?
常见图计数
(有向图计数板块还没写,下次一定补)
树(有标号)
虽然大家一定都知道n个点的树有n^(n-2)个。
方法来源于这篇博客。
写有标号有根树的指数型生成函数 (T(x) = xexp(T(x))),则 (frac{T(x)}{exp(T(x))}=x)。记 (G(x) = frac{x}{exp(x)}),则 (G(T(x)) = x)。
然后套拉格朗日反演得 ([x^n]T(x) = frac{[x^{n-1}](frac{x}{G(x)})^n}{n} = frac{[x^{n-1}]e^{nx}}{n} = frac{n^{n-1}}{n!})。
有标号有根树 (n^{n-1}),有标号无根树 (n^{n-2})。
仙人掌(有标号)
大概思路就是统计有根仙人掌的指数型生成函数(最后第 n 项要乘上 ((n-1)!))。
考虑根,它会连出去一些单边,每条单边的贡献为 (C(x))。
除此之外它会在一些环中,因为每种环对称过来也是环,所以大小为 i 的环的贡献为 (frac{C^{i-1}(x)}{2})。
因此总的贡献为 (exp(C(x) + sum_{i>1}frac{C^{i}(x)}{2}) = exp(frac{2C(x)-C^2(x)}{2-2x}))。
再算上根就可以得到 (C(x) = xexp(frac{2C(x)-C^2(x)}{2-2x})),牛顿迭代即可。具体式子有些长,可以看看这篇博客。
模板题。
点双连通图
与树/仙人掌的推导不同,点双连通图并不是通过较小的点双连通图递推得到,而是建立它与一个更简单的生成函数的联系。
设有根连通无向图指数型生成函数 (D(x)),点双连通图指数型生成函数 (B(x))。
(D(x)) 对所有无向图求个 ln 就求出来了(当然也可以容斥,变成多项式求逆)。
考虑如何由 (B(x)) 求 (D(x)),我们分析 (D(x)) 中根所在的若干点双连通分量。
对于根所在的某个大小为 i 的点双连通分量,它的贡献为 (frac{b_{i}D^{i-1}(x)}{(i-1)!})。因为点双内所有点等价,一种方案会被重复计算 ((i-1)!) 次,所以需要除以 ((i-1)!)。
那么包含所有点双就套个 (exp),变成 (exp(sum_{i=1}frac{b_{i+1}D^{i}(x)}{i!}) = exp(B'(D(x))))。
把根加入,得到等式 (D(x) = xexp(B'(D(x))))。变形得到 (B'(D(x)) = lnfrac{D(x)}{x})。
令 (H(x) = lnfrac{D(x)}{x}) 就可以扩展拉格朗日反演了。模板题。
边双连通图
与点双很类似,但也有些不同。
设有根连通无向图指数型生成函数 (D(x)),有根边双连通图指数型生成函数 (B(x))。
一样地,我们分析 (D(x)) 中根所在的边双连通分量,假设该边双大小为 i。
此时边双中一个点可以接多条边,如果用点双的方法(统计连通分量每个点的贡献)不太行。我们考虑对于每条接边双的边的贡献。
一条边可以接边双中的任意点,因此贡献为 (iD(x))。所有边的贡献,套个 (exp) 变成 (exp(iD(x)))。
那么大小为 i 的边双贡献为 (frac{b_ix^i}{i!}exp(iD(x)))(边双内 i 个点等价,所以除以 (i!))。
update in 2020/07/09:这里的除以阶乘含义与点双不同,直接理解为指数型生成函数那个除以阶乘即可。去重在 (exp) 中体现。
得到等式 (D(x) = sum_{i=1}frac{b_ix^i}{i!}exp(iD(x)) = B(xexp(D(x))))。然后扩展拉格朗日反演。
树(无标号)
有根
对于有标号的情况,我们不难写出 (F(x) = xexp(F(x)))(指数型生成函数)。
对于无标号的情况,我们类似地定义出 Euler变换 (xi(F(x))),使得 (F(x) = xxi(F(x)))(普通型生成函数)。
其中 (xi(F(x))=prod_{i}(1+x^i+x^{2i}+dots)^{f_i}=prod_i(1-x^i)^{-f_i}),可以理解成完全背包的过程。
然而这个定义不是很优美。我们可以用 (ln) 进行简化(也可以用 burnside 引理)。
接着两边求导去掉 (ln)。
记 (G(x) = sum_{j=1}F'(x^j)x^j = sum_{j=1}sum_{i}i imes f_i imes x^{ij}),可得 (g_n = sum_{i|n}i imes f_i)。
然后就是分治 fft。当然本题也有牛顿迭代的解法,详见下方无根情况模板题的题解部分。主要是我自己都还没弄懂。
无根
首先你得做一遍无标号有根树。
不难联想到烷烃计数的方法,用点等价类减边等价类加对称边个数得到无根树个数。
可以考虑强制重心为根,减去不是以重心为根的方案。即减去根的最大子树 > (lfloor frac{n}{2} floor) 的方案数。相当于减去了 (sum_{i=lfloor frac{n}{2} floor+1}^{n}f_i imes f_{n-i})。
不过对于两个重心的情况,当两个重心对应的两棵子树不相同时还是会算重,所以当 n 为偶数时还要减去 (frac{f_{n/2}(f_{n/2}-1)}{2})。
可以用卷积优化然后解决多组询问,不过本题单组询问直接算就好了。
仙人掌(无标号有根)
设其普通型生成函数为 (A(x))
仿照有标号仙人掌,我们讨论根所在的若干环与单边。
注意到单边可以等价地视作重边构成的环,所以下文只考虑环的情况。
不难想到包含 i 个点的贡献为 (A^{i-1}(x)) 再减去重复计数的情况。
我们考虑没有重复计数的情况,即将环翻转后长得一样的情况。
记 (B(x) = A(x)B(x) + A(x)) 表示不考虑重复计数的方案数。
记 (C(x) = A(x^2)C(x) + A(x)) 表示除去根包含奇数个点的,翻转后长得一样的方案数。
记 (D(x) = frac{B(x) + C(x) + B(x^2)}{2}) 表示已经减去重复计数的方案数。
那么 ({b_i}, {c_i}, {d_i}) 可以通过 ({a_i}) 递推得到,这一部分可以分治 fft。
考虑 ({a_i}) 的求解。仿照无标号树的计数方法,列出欧拉变换 (A(x) = xxi(D(x)))。然后也可以套分治 fft 求。
模板题(hdu好像出了点问题,不知道为什么提交不了)
update in 2020/06/06:把 length 这个函数名改了就让过了。好像是在编译时被识别为攻击网站的代码,然后编译到一半就不给编译了->_->
其他
loj - 2983:「WC2019」数树:关于多项式 exp 在优化卷积式中的实际应用。
考虑指数型生成函数 (A(x), B(x)),式子 (ln A(x) = B(x))((A(x) = e^{B(x)}))对应的卷积式。
两边求导得 (ln' A(x) = frac{A'(x)}{A(x)} = B'(x)),即 (A'(x) = A(x)B'(x))
求导左移,积分右移。对比两边第 n - 1 项:
把 (B(x)) 看作元素的生成函数(如有标号树的生成函数),(A(x)) 看作集合的生成函数(如有标号森林的生成函数)。
相当于钦定一个特殊元素(如包含标号最小点的树),类似背包,将这个元素放进去。
关于这点的理解,你还可以从 exp 的泰勒展开来看:(A(x) = e^{B(x)} = sum_{i=0}frac{B^i(x)}{i!})。
有时候需要对 (B(x)) 进行移位处理(求导积分)才能套用 exp。 (B(x)) 只在等式一边出现所以移位是可行的。
loj - 2320:「清华集训 2017」生成树计数:关于幂等和 (s_k = sum_{i=0}^{n}a_i^k) 的求法以及在化式子中的应用。
假如已知 n 个数 (a_{1dots n}),如何去求 (s_k = sum_{i=0}^{n}a_i^k) 的生成函数 (S(x) = sum_{i=0}s_ix^i)?
方法很多(真的很多),这里介绍我常用的一种:
注意到 (ln(1 - x)=-sum_{i=1}frac{x^i}{i}),我们只需要求出 (sum_{i=1}^{n}ln(1-a_ix)) 的生成函数,作一些转化就可以得到 (S(x))。
而 (sum_{i=1}^{n}ln(1-a_ix) = ln(prod_{i=1}^{n}(1 - a_ix))),分治 fft 即可。
有些时候,如果 n 个参数 (a_{1dots n}) 对应的生成函数有着类似的形式 (P(a_i x)),最后化出来的式子中的 (sum_{i=1}^{n} P(a_i x)) 或 (prod_{i=1}^{n} P(a_i x) = exp(sum_{i=1}^{n}ln(P(a_ix)))) 就可以做幂等和。
这样的话就不用再设 n 个生成函数 (P_i(x) = P(a_ix)),对于化式子方便一些。
用生成函数解斐波那契数列。
设 (F(x) = sum_{i=0}f_ix^i)。根据斐波那契数列的递推式 (f_n = f_{n-1} + f_{n-2}) 以及边界情况 (f_0 = 0, f_1 = 1),可得 (F(x) = xF(x) + x^2F(x) + x),即 (F(x) = frac{x}{1 - x - x^2})。
如果要得到通项公式,需要对其裂项。由于 (1-x-x^2 = (1-frac{1-sqrt{5}}{2}x)(1-frac{1+sqrt{5}}{2}x)),不妨设 (F(x) = frac{A}{1-frac{1-sqrt{5}}{2}x} + frac{B}{1-frac{1+sqrt{5}}{2}x}=frac{(-frac{1-sqrt{5}}{2}B-frac{1+sqrt{5}}{2}A)x+(A+B)}{1-x-x^2})。
解一下方程得到 (A = -frac{1}{sqrt{5}}, B = frac{1}{sqrt{5}}),因此 (F(x) = frac{-frac{1}{sqrt{5}}}{1-frac{1-sqrt{5}}{2}x} + frac{frac{1}{sqrt{5}}}{1-frac{1+sqrt{5}}{2}x})。
得到通项 (f_n = frac{1}{sqrt{5}}[(frac{1+sqrt{5}}{2})^n - (frac{1-sqrt{5}}{2})^n])。
有些题可能要你通过类斐波那契数列通项式逆向构造递推式然后矩阵快速幂,比如 loj - 2106:「JLOI2015」有意义的字符串。
当然,仅仅是通过生成函数研究斐波那契数列是无法研究出它所有性质的。
用生成函数解卡特兰数。
记 (C(x) = sum_{i=0}c_i x^i),根据卡特兰数递推式 (c_{n+1} = sum_{i=0}^{n}c_ic_{n-i}) 以及边界条件 (c_0 = 1),可得 (C(x) = xC^2(x) + 1)。
解二次方程可得 (C(x) = frac{1pmsqrt{1-4x}}{2x})。根据常数项舍去一根,得到 (C(x) = frac{1-sqrt{1-4x}}{2x})。
我们尝试构造出 (C(x)) 更简洁的递推式。对于 (sqrt{f(x)}) 有一种常用的方法就是求导(比如 loj - 2105:「TJOI2015」概率论)
求导可得 (G'(x) = frac{(2x-1)sqrt{1-4x}-4x+1}{8x^3 - 2x^2} = frac{-2xG(x)+G(x)+1}{4x^2-x})。
因此 ((4x^2-x)G'(x) + (2x-1)G(x) = 1)。对比系数得到 (4(n-1)f_{n-1} - nf_{n} + 2f_{n-1} - f_{n} = 0),即 (f_n = frac{4n-2}{n+1}f_{n-1})。
这样可以 (O(n)) 求出卡特兰数以及类似的数列(如 codechef - JADUGAR2:Chef and Same Old Recurrence 2)。
一样地,仅仅研究生成函数无法研究出卡特兰数的所有性质。
两个需要记住的生成函数封闭形式:
(sinh(x) = frac{e^x - e^{-x}}{2}) 表示只取 (e^x) 展开的奇数项。
(cosh(x) = frac{e^x + e^{-x}}{2}) 表示只取 (e^x) 展开的偶数项。
可以使用这两个生成函数的封闭形式进行二项式定理展开之类的操作(比如loj - 3120:「CTS2019 | CTSC2019」珍珠)。