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_{i, j, 0} = min \begin{cases} f_{i - 1, j, 0} + W_{C_{i - 1}C_i}\\ f_{i - 1, j, 1} + K_{i - 1} \times W_{D_{i - 1}C_i} + (1 - K_{i - 1}) \times W_{C_{i - 1}C_i} \end{cases}\]

\[f_{i, j, 1} = min \begin{cases} f_{i - 1, j - 1, 0} + K_i \times W_{C_{i - 1}D_i} + (1 - K_i) \times W_{C_{i - 1}C_i}\\ f_{i - 1, j - 1, 1} + K_{i - 1} \times K_i \times W_{D_{i - 1}D_i} + K_{i - 1} \times (1 - K_i) \times W_{D_{i - 1}C_i} + \\ (1 - K_{i - 1}) \times K_i \times W_{C_{i - 1}D_i} + (1 - K_{i - 1}) \times (1 - K_i) \times W_{C_{i - 1}C_i} \end{cases}\]

答案即为 \(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\)。那么第二次切时有:

\[b_2 = \lfloor p \times max(a_2 + q, b_1) \rfloor \leq \lfloor pa_1 \rfloor + q = b_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)\)

关键字: 动态规划

posted @ 2017-05-25 21:36  lijingze8  阅读(134)  评论(0)    收藏  举报