NOIP2016
D1T2. Running (2s, 512MB)
题目大意: 给定一棵 \(n\) 个结点的树,第 \(i\) 个结点有权值 \(W_i\)。给定树上 \(m\) 条路径 \((S_j, T_j)\)。定义若结点 \(i\) 在路径 \(j\) 上,应满足:
- \(i\) 在从 \(S_j\) 到 \(T_j\) 的路径上
- \(i\) 到 \(S_j\) 的距离为 \(W_i\)
求对于每个结点 \(i\),其在多少条路径上。
数据范围: \(1 \leq n, m \leq 300000\)
简要题解: 先约定如下符号的含义:
- \(d_i\) 表示结点 \(i\) 在树中的深度
- \(f_i\) 表示结点 \(i\) 的父亲结点
- \(l_i\) 表示路径 \(i\) 在树中的长度
- \(lca_i\) 表示 \(S_i\) 和 \(T_i\) 的最近公共祖先
画如下草图,图中标示了三种不同的路径形式:

易知询问结点 \(i\) 在多少条路径上,即是询问满足下列两种情况之一的路径条数:
- 在结点 \(i\) 所在的子树中,有多少 \(S_j\) 满足 \(d_{S_j} = d_i + W_i\)
- 在结点 \(i\) 所在的子树中,有多少 \(T_j\) 满足 \(d_{T_j} = d_i + (l_j - W_i)\),即 \(d_{T_j} - l_j = d_i - W_i\)
但这两种情况会有重复的部分:当 \(i = lca_j\) 时,第 \(j\) 条路径会在结点 \(i\) 处被统计两次。我们考虑将一条路径 \((S_j, T_j)\) 拆分成 \((S_j, lca_j)\) 和 \((x, T_j)\) 两条路径来进行处理。其中结点 \(x\) 为结点 \(lca_j\) 的儿子结点中可以到达 \(T_j\) 的那个,比如上图中的 7 号结点。
对于第一种路径 \((S_j, lca_j)\),易知,这条路径仅会影响到 \((S_j, lca_j)\) 上的所有结点的答案。考虑在路径上打标记。我们 dfs 整棵树,令 \(A_i\) 表示当前记录了多少 \(S_j\) 满足 \(d_{S_j} = i\)。当 dfs 到 \(S_j\) 时,将 \(A_{d_{S_j}}\) 加一,当 \(f_{lca_j}\) 退栈时,将 \(A_{d_{S_j}}\) 减一。那么第一种路径对结点 \(i\) 答案的贡献即为 \(A_2 - A_1\),其中 \(A_1\) 和 \(A_2\) 分别为结点 \(i\) 进栈和退栈时 \(A_{d_i + W_i}\) 的值。
对于第二种路径 \((x, T_j)\),同理,当 dfs 到 \(T_j\) 时,将 \(B_{d_{T_j} - l_j}\) 加一,当 \(lca_j\) 退栈时,将 \(B_{d_{T_j} - l_j}\) 减一。那么第二种路径对结点 \(i\) 答案的贡献即为 \(B_2 - B_1\),其中 \(B_1\) 和 \(B_2\) 分别为结点 \(i\) 进栈和退栈时 \(B_{d_i - W_i}\) 的值。
以上两种路径统计的答案之和即为所求。注意到求答案的过程中只需要 dfs,那么,整个算法的复杂度取决于求 \(lca_j\) 的复杂度,用 Tarjan 算法可以达到 \(O(n + m)\)。
时空复杂度: \(O(nlogn) / O(n + m) - O(n)\)
关键字: DFS,最近公共祖先
D1T3. Classroom (1s, 512MB)
题目大意: 给定一个 \(v\) 个点 \(e\) 条边的带权无向图。给定序列 \(\{C_n\}\),表示要依次经过这些点。再给定序列 \(\{D_n\}\) 和 \(\{K_n\}\),表示在一次操作中,可以选择一个没有被选过的 \(i\),有 \(K_i\) 的概率将 \(C_i\) 替换为 \(D_i\)。若最多可以进行 \(m\) 次操作,求依次经过新序列中的每个点,所要走最小总路程的期望值。依次经过理解为每次从序列中的第 \(i\) 个点走到第 \(i + 1\) 个点即可,而忽视在该过程中途经的点。
数据范围:\(1 \leq n \leq 2000\),\(0 \leq m \leq 2000\),\(1 \leq v \leq 300\),\(0 \leq e \leq 90000\),\(0 \leq K_i \leq 1\),\(1 \leq C_i,D_i \leq v\)
简要题解: 显然,用 Floyed 算法可以求出 \(W_{ab}\) 表示 \(a\),\(b\) 之间的最短路。令 \(f_{i, j, 0..1}\) 表示考虑了序列的前 \(i\) 个位置,已经进行了 \(j\) 次操作,当前位置是否进行操作时的最小总路程期望值。那么,转移方程为:
答案即为 \(f_n\) 中的最小值。
时空复杂度: \(O(v ^ 3 + nm) - O(v ^ 2 + nm)\)
关键字: 动态规划
D2T2. Earthworm (1s, 512MB)
题目大意: 现有 \(n\) 只长分别为 \(a_i\) 的蚯蚓,每一时刻会选择最长的一只将其切成两只。设这只最长的蚯蚓长为 \(x\),则会将其切为长 \(\lfloor px \rfloor\) 和 \(x - \lfloor px \rfloor\) 的两只。同时,除这两只新产生的蚯蚓外,其余蚯蚓均会变长 \(q\)。求在 \(m\) 个时刻中,每次被切的蚯蚓长度和在 \(m\) 个时刻后,各蚯蚓的长度。
数据范围: \(n \leq 10^5\),\(m \leq 7 \times 10^6\),\(0 \leq a_i \leq 10^8\),\(0 < p < 1\)
简要题解: 先将 \(n\) 只蚯蚓按长度从大到小排序,则第一次切的蚯蚓长度为 \(a_1\),设其被切成 \(b_1 = \lfloor pa_1 \rfloor\) 和 \(c_1 = a_1 - \lfloor pa_1 \rfloor\),不妨令 \(b_1 \geq c_1\)。那么第二次切时有:
同理有 \(c_2 \leq c_1\)。由此可知若每次将切成的蚯蚓中较长的加在 \(b\) 队列后,较短的加在 \(c\) 队列后,形成的 \(b\),\(c\) 队列均为非增队列。则我们只要用以上方式维护队列 \(a\),\(b\),\(c\),就可以保证三者均有序,那么每次被切的最长蚯蚓即为队列 \(a\),\(b\),\(c\) 队首元素中的最大值,最后归并一下即可得到 \(m\) 个时刻后的蚯蚓长度序列。
时空复杂度: \(O(nlogn + m) - O(n + m)\)
关键字: 单调性,归并
D2T3. Angrybirds (2s, 512MB)
题目大意: 在二维平面上有 \(n\) 只小猪分别位于 \((x_i, y_i)\),在 \((0, 0)\) 处可以发射运动轨迹为 \(y = ax^2 + bx\) 的小鸟,其中 \(a, b \in \mathbb{R}\) 且 \(a < 0\)。若某只小鸟的运动轨迹经过了 \((x_i, y_i)\),那么第 \(i\) 只小猪就会被消灭掉,且该小鸟会沿原先轨迹继续运动。求至少要发射多少只小鸟,才能消灭所有小猪。
数据范围: \(1 \leq n \leq 18\),\(0 < x_i, y_i < 10\)
简要题解: 用二进制数记录已消灭的小猪的状态,令 \(f_i\) 为达到状态 \(i\) 时所需要发射的最少小鸟数。状态转移时可以固定一只小猪要在这次发射中被消灭,这样只要枚举另一只未被消灭的小猪即可,降低时间复杂度。
时空复杂度: \(O(n^22^n) - O(2^n)\)
关键字: 动态规划

浙公网安备 33010602011771号