0%

CF-1072-F. Cherry Tree(不要忘记 dp,特别是子问题相互重叠之时)

题目大意

给定一棵有 n 个顶点的有根树,根节点为 1。每个叶子节点上都有一个樱桃。

你需要通过"摇动"顶点来收集所有樱桃。摇动顶点 v 时,所有作为 v 后代的叶子节点上的樱桃都会掉落。每个叶子的樱桃只能掉落一次,否则树会损坏。

关键限制:摇动的顶点数量必须是 3 的倍数

问题:是否可能在满足上述条件下收集所有樱桃?

输入格式:

  • 第一行:测试用例数 t (1 ≤ t ≤ 10⁴)

  • 每个测试用例:第一行为 n (2 ≤ n ≤ 2×10⁵),接下来 n-1 行描述树的边

**输出格式:**对每个测试用例输出 “YES” 或 “NO”

思路讲解

当你发现一个问题的子结构之间互相重叠覆盖,其中还涉及这个决策的时候,这个时候,你就要想,是不是 dp 了。

树上 dp,定义状态为 dpu,idp_{u,i},指的是以 uu 为根的子树中,是否可以凑出来为这个 i (0,1,2)i\ (0,1,2) 的这个 3 的余数。

接着问题就来到了如何转移?我们不妨定义,toto 为转移过来的子节点,四个你可以理解为 bitset 的东西,长度为 3,bibi 为目前的状态,若 dpto,0dp_{to,0} 为 true,那么 bi1bi1 就是这个 bibi 向前循环移动的结果,否则 bi1bi1 为全 0。同理,我们可以定义出 bi0bi0bi2bi2。最终经过这个 toto 节点的转移后,bibi0bi1bi2bi\gets bi0 \lor bi1 \lor bi2。(当然,第一个 toto 节点转移过来的话,为了初值确定,bidptobi\gets dp_{to}

最后,令 bi1truebi_1\gets \text{true}(因为我们始终可以选择子树根节点,来解决这个问题),接着 dpubidp_u\gets bi

为什么要这么转移?我们会发现,就是说如果子树只有一个唯一的位移的话,是不是只是让这个状态进行一个位移?那么其实只有一个位移是没什么大用的,但是如果有两种位移?三种位移?这几种位移之间如何组合?那么答案就昭然若揭了。

AC代码

AC
https://codeforces.com/contest/2184/submission/357994744

心路历程(WA,TLE,MLE……)

image