CF1010F 与 ABC269H:有多少个包含根的连通块?

CF 传送门

AT 传送门

两题主要 Trick 相同。CF 的还多了一个小 trick。


给定一棵根节点为 1 的二叉树 T,你需要先保留一个包含 1 号节点的连通块,然后给每个点确定一个权值 ai,使得对于每个点 u 都有其权值 au 大于等于其所有儿子的权值和 av[(u,v)T]

最后,你需要使得根节点权值为 x,求方案数,答案对 998244353 取模。

n105,x1018.

auvson(u)av0,令 bu=auvson(u)av,即 bu0。注意到 bu=x,且 {ai}{bi} 一一对应,所以分配 ai 相当于分配 bi。而如果选了固定 k 个点,分配 bi 就是把 x 分给 k 个数,每个数 0。这是经典结论,有 (x+k1k) 种分配方式。

于是下面的问题就是对于每个 k=1n,求出有多少个 k 大小的包含 1 的连通块。

法一:普通树形 DP。dp[i][j] 表示在 i 的子树内选 j 个点的方案数。转移方程 dp[i][j]dp[i][j]+vson(i),k<jdp[i][k]dp[v][jk]。因为每一对点的复杂度在其 LCA 处贡献 O(1) 次,复杂度是 O(n2) 的。

法二:dfs 序 DP。dp[i][j] 表示考虑 dfs 序 <i 的结点选不选,共选了 j 个的方案数。转移方程 dp[i][j]dp[i+1][j+1]dp[i][j]dp[mxi+1][j]。复杂度 O(n2)

法三:FFT + 树剖优化法一。注意到法一 dp[i][k]dp[v][jk] 的形式是卷积,考虑使用 FFT 优化。转移方程为 F(u)=xF(son1)F(son2)+1

但是直接上复杂度是 O(n2logn) 的,因为两个式子卷积 O(lenloglen),所以每一对点贡献的复杂度变成 O(logn) 了。

难道这个做法没有用吗?不,我们还有办法!上面做法的问题在于每个点会被使用太多次了。有什么办法是让一个点出现次数变少的?

树剖!我们进行重链剖分,仅在重链链顶处统计重链上所有的点和轻儿子的贡献。

如图。在重链链顶 u1 处计算 F(u1),可以一路分解下去到轻儿子。记相关的多项式为 a1a4,要求的形式即为 1+a1+a1a2+a1a2a3+a1a2a3a4,而 ai 的大小之和是 O(n) 的。这种形式可以用分治 FFT 计算。

具体而言,我们在计算 a1++a1an 时,先递归计算 a1++a1an/2an/2+1++an/2+1an 部分。同时让这两部分额外返回 a1an/2an/2+1an 的值,则当前结果即为 a1++a1an/2+a1an/2(an/2+1++an/2+1an),用一次多项式加法和一次多项式乘法可以 O(nlogn) 做到。

分治 O(logn) 层,每层 O(nlogn) 合并。所以计算重链链顶多项式的复杂度是 O(nlog2n) 的。(这里的 n 是所在重链轻子树大小之和)

所以一个结点在作为轻儿子时会贡献 O(log2) 的复杂度,每个结点贡献 O(logn) 次,总复杂度 O(nlog3n)

posted @   FLY_lai  阅读(7)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 阿里最新开源QwQ-32B,效果媲美deepseek-r1满血版,部署成本又又又降低了!
· 单线程的Redis速度为什么快?
· SQL Server 2025 AI相关能力初探
· AI编程工具终极对决:字节Trae VS Cursor,谁才是开发者新宠?
· 展开说说关于C#中ORM框架的用法!
点击右上角即可分享
微信分享提示