1 条题解
-
0
D. Tree Jumps 详细题解
问题理解
我们有一棵以 为根的有根树,每个顶点 的距离 定义为从根到 的边数(根的距离为 )。
初始时棋子在根节点 。每次操作可以将棋子从当前节点 移动到某个节点 ,满足 (即必须往下一层走),并且:
- 如果 是根节点,可以跳到下一层的任意节点
- 如果 不是根节点,则 不能是 的邻居(即不能是 的父节点或子节点)
注意:由于 , 只能是 的孩子节点或下一层的其他非孩子节点。但“不能是邻居”这个条件禁止跳到孩子节点(因为孩子是邻居),所以当 不是根时,只能跳到下一层中不是自己孩子的节点。
一个顶点序列被称为有效,如果存在一种移动方式,使得棋子按顺序访问序列中的所有顶点(且只访问这些顶点,不能多也不能少)。
求所有有效序列的数量,对 取模。
关键观察
1. 序列必须从根开始
因为棋子初始在根,且只能向下走(),所以任何有效序列的第一个顶点必须是根 。
2. 序列中顶点的深度严格递增
每次操作深度 ,所以序列中顶点的深度必须严格递增:。
因此,一个有效序列对应一条从根出发的“路径”,但这条路径不一定是树上的连续路径,因为可以跳到非孩子节点。3. 移动规则的本质
设当前在深度 的节点 ,要跳到深度 的节点 :
- 如果 (即 是根):可以跳到深度 的任意节点
- 如果 :可以跳到深度 中除了 的孩子以外的任意节点
换句话说,从深度 的一个节点出发,能够到达的深度 节点集合 = 整个深度 的节点集合,减去该节点的孩子集合(当 时)。
动态规划思路
设 表示以顶点 结尾的有效序列的数量。
那么答案就是 。
边界条件
,因为序列 是有效的。
转移方程
对于非根节点 (深度 ),考虑它的所有可能前驱节点 (深度为 的节点),使得从 可以合法地跳到 。
从 跳到 合法的条件是:
- 如果 (即 是根):总是合法
- 如果 :需要 不是 的孩子
所以:
$$dp_v = \sum_{p \in \text{depth } i-1} [\text{可以从 } p \text{ 跳到 } v] \cdot dp_p $$令 表示深度 的所有节点,。
那么:
- 如果 (即 ):(因为深度 只有根,)
- 如果 :$dp_v = total_{i-1} - \sum_{p \text{ 是 } v \text{ 的父节点}} dp_p$
注意:一个节点 的父节点是唯一的,设为 。所以 $\sum_{p \text{ 是 } v \text{ 的父节点}} dp_p = dp_{f(v)}$。
因此,对于深度 的节点 :
其中 。
算法步骤
- 读入树,计算每个节点的深度
- 按深度分组,得到每层的节点列表
vs[d] - 初始化:
- 按深度 从 到最大深度遍历:
- 对于当前层的每个节点 :
- 如果 ( 在深度 ):
- 如果 :(模意义下)
- 计算
- 对于当前层的每个节点 :
- 答案 = (即所有 之和)
正确性证明
归纳法:假设对于深度 的所有节点, 值已正确计算(表示以该节点结尾的有效序列数)。
对于深度 的节点 ,所有以 结尾的有效序列,去掉最后一个节点 后,得到的是一个以某个深度 节点 结尾的有效序列,并且从 可以合法跳到 。
- 如果 : 只能是根,且根可以跳到任意深度 节点,所以 。
- 如果 : 可以是深度 的任意节点,除了 的父节点(因为不能从父节点跳到子节点)。所以 。
因此转移正确。
复杂度分析
- 计算深度:
- 按深度分组:
- 每层遍历:
- 总时间复杂度 ,每个测试用例
- 所有测试用例 之和 ,完全可行
示例验证(以第一个样例为例)
树结构:,父节点列表
深度:,,,- 深度 :,,
- 深度 :
- 深度 :,父节点
答案 = ,匹配输出。
总结
本题的核心是:
- 观察到移动规则等价于:从深度 的非根节点,可以跳到下一层的任意节点,除了自己的子节点
- 使用按深度分层的 DP,转移时用“当前层总和减去父节点贡献”
- 避免 的枚举,通过维护 实现 转移
这种“总合法前驱减去非法前驱”的技巧在树形 DP 中非常常见。
- 1
信息
- ID
- 7214
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者