NOI D1T1 合集

为了防止菜鸡 Scintilla 在 NOI2021 网络同步赛中保龄,他找了一些 NOI D1T1 来做。

NOI2020 D1T1 美食家

Description

给定一张 \(n\) 个点、\(m\) 条边的有向图,点 \(u\) 有点权 \(c_u\)、边 \(i\) 有边权 \(w_i\),有重边无自环。你需要在第 \(0\) 秒从 \(1\) 号点开始走,走一条边的秒数为其权值,经过一个点 \(u\) 可以获得 \(c_u\) 的收益。特别地,有 \(k\) 个特殊情况,每组特殊情况形如 \(t, x, y\),表示在第 \(t\) 秒走到点 \(x\) 可以额外获得 \(y\) 的收益。你需要在恰好第 \(t\) 秒回到 \(1\) 号点,求最大收益。

\(n \le 50, n \le m \le 501, k \le 200, w_i \le 5, c_i \le 52501\)

\(1 \le u_i, v_i, x_i \le n, t_i \le T \le 10^9, y_i \le 10^9\)

Solution

看到 \(n\) 很小、\(T\) 很大,第一时间想到矩乘。

一个显然的想法是设 \(f_{i, j}\) 表示第 \(i\) 秒到达 \(u\) 号点的最大收益、\(g_{i, u}\) 表示在第 \(i\) 秒到 \(u\) 号结点的额外收益,那么转移就是

\[f_{i, u} = \max\limits_{(v, u, w) \in E} f_{i - w, v} + c_u + g_{i, u} \]

但是这个东西普通的矩乘貌似不能做,因为转移是 \(\max\) 形式的。首先考虑这样的 \(\max\) 转移是否具有结合律。

定义矩阵的 \(\oplus\) 操作(即上面的转移形式)为

\[(A \oplus B)_{i, j} = \max_{k}\{A_{i, k} + B_{k, j}\} \]

\(A, B, C\) 为三个矩阵,有

\[ \begin{aligned} ((A \oplus B ) \oplus C)_{i, j} &= \max\limits_p \{\max\limits_q \{A_{i, q}, B_{q, p}\} + C_{p, j}\} \\ &= \max\limits_q \{A_{i, q} + \max\limits_p \{B_{q, p}, C_{p, j}\}\} \\ &= (A \oplus (B \oplus C))_{i, j} \end{aligned} \]

所以这里的结合律依然存在,快速幂依然有用。但是还有一个问题我们没有处理——特殊情况。因为 \(k \le 200\),我们可以把特殊情况按照 \(t\) 排序,乘到一个 \(t\) 就停下来将对应的值加上额外收益,再继续乘即可,但这样的时间复杂度 \(\mathcal{O}((5n)^3k \log T)\),有点爆炸。

设转移矩阵为 \(T\),DP 矩阵为 \(F\)。发现我们每一次都是先乘好 \(T\) 的幂次再把 \(F\) 和它乘,但事实上我们可以预处理出 \(T\)\(2^i\) 次幂,每次都拿 \(F\)\(T\)\(2^i\) 次幂乘,因为 \(F\)\(T^{2^i}\) 的一次乘法是 \(\mathcal{O}((5n)^2)\) 的,所以可以将复杂度降至 \(\mathcal{O}((5n)^3 \log T + (5n)^2k \log T)\),可以接受。


NOI2019 D1T1 回家路线

Description

\(n\) 个点,你在第 \(0\) 时刻位于第一个点,你需要走到第 \(n\) 个点。有 \(m\) 班列车,第 \(i\) 班列车在时刻 \(p_i\) 从点 \(x_i\) 出发,在时刻 \(q_i\) 到达点 \(y_i\),只能在时刻 \(p_i\) 上车、时刻 \(q_i\) 下车。给定函数 \(f(x) = Ax^2 + Bx + C\),设 \(s_1, \cdots, s_k\) 为一个合法的回家列车序列,定义这个序列的代价为

\[q_{s_k} + f(p_{s_1}) + \sum\limits_{i = 2} ^ k f(p_{s_i} - q_{s_{i - 1}}) \]

求所有合法回家列车序列的最小代价。

原题数据范围:\(n \le 10^5, m \le 2 \times 10^5, A \le 10, B, C \le 10^6, 0 \le p_i < q_i \le 10^3\)

加强版数据范围:\(n \le 10^5, m \le 10^6, A \le 10, B, C \le 10^7, 0 \le p_i < q_i \le 4 \times 10^4\)

Solution

预处理出从每个点出发和到每个点的列车,把所有列车按照 \(q\) 排序,设 \(f_i\) 为乘坐第 \(i\) 号列车时的最小代价,那么转移显然,这样暴力做就能拿到 \(70\) 分。

一个想法是斜率优化,但是发现能够转移的点并不连续,所以不能直接莽斜率优化。我们可以对 \(p\) 的值域分块,但这样还是过不了加强版。不过直接把所有 \(p_i\) 的询问离线即可,换句话说就是把一条边拆成加数和查询两个操作,可以直接按照时间排序。时间复杂度 \(\mathcal{O}(m \log m)\)

注意斜率优化时判横坐标相等!!!


NOI2018 D1T1 归程

Description

给定一张 \(n\) 个点和 \(m\) 条边的图,每条边有一个长度和一个权值。有 \(q\) 组询问,每组询问给定两个数 \(u\)\(p\)。对于一条 \(u \to 1\) 的路径,设 \(v\) 为路径上从 \(u\) 开始第一条权值不大于 \(p\) 的边离 \(u\) 较远的那个结点(若不存在这样的边则令 \(v \leftarrow 1\)),定义这条路径的代价为 \(v \to 1\) 路径上边的长度和,询问 \(u \to 1\) 所有路径的最小代价。

强制在线,\(n \le 2 \times 10^5, m \le 4 \times 10^5, q \le 4 \times 10^5\)

Solution

  • 关于 \(\rm SPFA\)
  • 它死了

首先我们需要知道一个叫做 Kruskal 重构树的东西。

Kruskal 重构树是一棵部分点有点权的树。它的构造方法如下:在 Kruskal 算法进行的过程中,对于加入的第 \(i\) 条边,新建一个编号为 \(n + i\) 的结点,它的两条边连向合并的两个集合的根,并将它的点权设为当前这条边的长度,然后将新节点设为根。不难发现最后形成了一个二叉树的结构,我们就把这棵树称为 Kruskal 重构树。

那么 Kruskal 重构树有什么性质呢?不难发现,最小生成树上两个结点简单路径上的最大权值就是他们 LCA 的点权。

回到原题。不难发现可以找到至少一条答案路径在原图的权值最大生成树上,结合上面的性质,发现所有符合要求的点就是以 \(u\) 的所有祖先中权值深度最小的权值大于 \(p\) 的结点的子树。于是我们可以预处理出子树内部的点到 \(1\) 号点的 \(\min\) 值、找到那个点可以树上倍增。

时间复杂度 \(\mathcal{O}(n \log n)\)(默认 \(n, m, q\) 同阶)。


NOI2017 D1T1 整数

Description

有一个整数 \(x\),刚开始为 \(0\),你需要支持两种操作:

  • 给定整数 \(a\) 和非负整数 \(b\),令 \(x \leftarrow x + a \cdot 2^b\)
  • 给定整数 \(k\),询问 \(x\) 二进制下代表 \(2^k\) 的一位的值。

\(n \le 10^6, |a| \le 10^9, b, k \le 30n\),保证任何时刻 \(x\) 非负。

Solution

一个想法是用 bitset 之类的维护 \(x\) 这个数,但是因为 \(a\) 可能为负,这个算法的时间复杂度会退化到 \(\mathcal{O}(\frac{k^2 \log |a|}{\omega})\)

发现修改是区间赋值,又看到 \(30n\) 这个奇妙的东西,可以压位上线段树,时间复杂度 \(\mathcal{O}(n \log n \log a_i)\),貌似可以艹过去。

posted @ 2021-07-26 08:18  Scintilla06  阅读(200)  评论(0编辑  收藏  举报