[BZOJ3456] 城市规划(的拓展)

本文探讨了求解nnn个点的无向连通图个数的经典问题,通过生成函数和微分方程的巧妙结合,提出了一种在O(nlogn)时间内求解的高效算法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

前言

最近看到一道经典的题目,就是这一题了。

题意:求 nnn 个点的无向连通图的个数。

题意很简洁,做法也很自然。因为本篇重点不在这一道题,因此这里只做一个简短的说明:

不妨设答案的生成函数为 ∑i=1∞fixi\sum\limits_{i=1}^{\infty} f_ix^ii=1fixi

我们知道我们可以取任意多任意大小的连通块生成一张无向图,而 nnn 个点的无向图个数共有 2n(n−1)22^{\frac{n(n-1)} {2}}22n(n1) 个。

f(x)=∑i=1∞fii!xif(x)=\sum\limits_{i=1}^{\infty}\frac{f_i}{i!}x^if(x)=i=1i!fixi

根据指数型生成函数的知识我们有:ef(x)=∑i=0∞2i(i−1)2i!xie^{f(x)}=\sum\limits_{i=0}^{\infty} \frac{2^{\frac{i(i-1)} {2}}} {i!}x^ief(x)=i=0i!22i(i1)xi

多项式求 ln⁡\lnln 即可。

正文

显然,联通图可以理解为连通块个数等于 111

如果是连通块个数等于 kkk 的方案数,我们只需要求 fkf^kfk 就可以了,注意到同一张图会被生成 k!k!k! 次(生成的排列共有 k!k!k! 种),因此答案的指数型生成函数是 fkk!\frac{f^k} {k!}k!fk

那如果是连通块个数 ≤k\le kk 的方案数呢?

很显然,把 111kkk 的函数求和即可(下文为了方便实际上还把函数加了一个常数 111 ,不过并没有什么影响):

G(x)=ex mod xk+1G(x)=e^x \bmod x^{k+1} G(x)=exmodxk+1

F(x)=G(f(x))=∑i=0kfi(x)i!F(x)=G(f(x))=\sum\limits_{i=0}^{k}\frac{f^i(x)} {i!}F(x)=G(f(x))=i=0ki!fi(x)

现在的问题在于如何求 F(x)F(x)F(x)

暴力乘卷积优化的复杂度为 O(n2log⁡n)O(n^2\log n)O(n2logn)

使用快速计算复合函数的算法的话,就是 O((nlog⁡n)1.5)O((n\log n)^{1.5})O((nlogn)1.5)

当然,以上两种做法都没有用到 FFF 的特殊性质。

我们知道 exe^xex 的重要特性是导数与原函数相等。

G(f)=ef mod fk+1G(f)=e^f \bmod f^{k+1}G(f)=efmodfk+1

不妨对两边同时求导:

G′(f)=ef mod fkG'(f)=e^f \bmod f^{k}G(f)=efmodfk

两式对减:

G(f)−G′(f)=fkk!G(f)-G'(f)=\frac{f^k} {k!}G(f)G(f)=k!fk

FFF 替换 GGG

F(x)−F′(x)f′(x)=fk(x)k!F(x)-\frac{F'(x)} {f'(x)}=\frac{f^k(x)} {k!}F(x)f(x)F(x)=k!fk(x)

这就是一个很典型的一阶微分方程了。

于是我们有:

F′(x)−F(x)f′(x)=−fk(x)f′(x)k!F'(x)-F(x)f'(x)=-\frac{f^k(x)f'(x)} {k!}F(x)F(x)f(x)=k!fk(x)f(x)

e−f(x)(F′(x)−F(x)f′(x))=−fk(x)f′(x)e−f(x)k!e^{-f(x)}(F'(x)-F(x)f'(x))=-\frac{f^k(x)f'(x)e^{-f(x)}} {k!}ef(x)(F(x)F(x)f(x))=k!fk(x)f(x)ef(x)

(F(x)e−f(x))′=−fk(x)f′(x)e−f(x)k!(F(x)e^{-f(x)})'=-\frac{f^k(x)f'(x)e^{-f(x)}} {k!}(F(x)ef(x))=k!fk(x)f(x)ef(x)

因此有:

F(x)=ef(x)∫−fk(x)f′(x)e−f(x)k!dxF(x)=e^{f(x)}\int -\frac{f^k(x)f'(x)e^{-f(x)}} {k!}dxF(x)=ef(x)k!fk(x)f(x)ef(x)dx

这样子就可以在 O(nlog⁡n)O(n\log n)O(nlogn) 时间内求解了。

个人认为这个解题思路相当巧妙,可以优化许多类似问题。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值