IOI2018

组合动作 \((\texttt{Easy} \ 2 / 1)\)

这里给一个询问串长度不大于 \(3n\) 的做法。

首先通过两次询问得到第一个字符,设剩下的三个字符为 \(a, b, c\)

假设已经确定了 \(0 \sim i - 1\),当前的答案为 \(s \ (|s| = i)\),我们考虑询问

\[s + \texttt{aa} + s + \texttt{ab} + s + \texttt{ba} \]

如果匹配长度为 \(i\),说明接下来一位为 \(\texttt{c}\)

如果匹配长度为 \(i + 1\),说明接下来两位为 \(\texttt{ac}, \texttt{bb}, \texttt{bc}\) 其中之一,再询问 \(s + \texttt{bb}\) 即可根据结果来判断。

如果匹配长度为 \(i + 2\),说明接下来两位为 \(\texttt{aa}, \texttt{ab}, \texttt{ba}\) 其中之一,再询问 \(s + \texttt{aa}\) 即可根据结果来判断。

一直询问下去即可。注意判最后一位。

排座位 \((\texttt{Medium} \ 4 / 2)\)

一种可行的判断方法是:在矩形四周加一圈 \(nm + 1\),则 \(x\) 合法当且仅当恰好有 \(4\)\(2 \times 2\) 的矩形,使得其中有奇数个数 \(\le x\)

使用线段树维护即可,时间复杂度 \(\mathcal{O}(nm \log nm)\)

狼人 \((\texttt{Easy} \ 1 / 3)\)

相当于找到一个点 \(u\),使得存在一条 \(s \to u\) 的路径,使得点的编号不小于 \(l\);并且存在一条 \(u \to t\) 的路径,使得点的编号不大于 \(r\)

建两棵 \(\rm Kruskal\) 重构树,则问题等价于在两棵树上分别选定一个点,求这两个点的子树有没有交。这容易转化为二维数点问题。

时间复杂度 \(\mathcal{O}(n \log n)\)

机械娃娃 \((\texttt{Easy} \ 3 / 2)\)

发现 \(n\)\(2\) 的幂次的时候很好做。不难想到把所有的触发器连向同一个开关,并让所有开关形成一棵满二叉树,这棵树共有 \(n - 1\) 个点。那么从左到右第 \(rev_i\) 个位置就是第 \(i\) 个走的,从 \(\left\lfloor \frac{rev_i}{2} \right\rfloor\) 向对应的点连一条边即可。

对于 \(n\) 不是 \(2\) 的幂次的情况,我们把 \(rev_i\) 最大的几个位置向 \(-1\) 连边即可。发现这样会导致连续很多个叶子节点向 \(-1\) 连边,那么这样的叶子节点是没有必要存在的,直接从它的父节点向 \(-1\) 连边即可,于是我们把点数缩减到了 \(\mathcal{O}(n + \log n)\) 级别。

高速公路收费 \((\texttt{Medium} \ 4 / 2)\)

只想到了一半!!!

首先通过一次询问求出最短路长度 \(L\)

发现我们可以通过二分在 \(\log m\) 次询问内求出一条最短路上的一条边。具体地,设当前的区间为 \([l, r]\),我们考虑把 \([l, mid]\) 内的边状态改为为 \(1\),然后进行询问。如果答案 \(= L\),则令 $ l = mid + 1$;否则把 \([l, mid]\) 内的边状态改为 \(0\),并令 \(r = mid\)。这样最后剩下的编号一定在一条最短路上。

设这条边为 \(x, y\),不妨设 \(x\) 为靠近 \(s\) 的一边,设 \(X\) 为所有满足 \(d(u, x) < d(u, y)\)\(u\)\(Y\) 为所有满足 \(d(u, x) > d(u, y)\)\(u\),我们把 \(X\) 按照到 \(x\) 的距离从小到大排序,那么 \(s\) 肯定在最后,我们可以二分 \(s\) 的位置,可以同样二分 \(t\)

于是总的询问次数不超过 \(\log m + \log |X| + \log |Y| + 1\),可以通过本题。

会议 \((\texttt{Medium} \ 4 / 4)\)

建出笛卡尔树,那么在询问 \([l, r]\) 时,选择 \(x\) 的答案就是 \(\sum_{l \le u \le r} a_{\text{LCA}(u, x)}\)。我们首先考虑暴力解决每个询问:假设当前的点 \(u\) 的范围是 \([l, r]\)、如果我们能够知道两侧的区间分别于询问区间的交的答案,我们枚举选择的点在 \(u\) 的哪一边就能合并答案了。

现在考虑一起处理所有询问。我们把把询问挂在其最大值所在的位置,对于点 \(u\) 维护区间 \([l, l], [l, l + 1], \cdots, [l, r]\) 的答案,那么就能算出选的点在询问区间最大值右侧的答案了,在左侧的情况把数列和询问翻转再做一遍即可。考虑信息如何合并,我们需要把区间 \([u + 1, x] \ (x = u + 1, \cdots, r)\) 的左端点改为 \(l\),并添加区间 \([l, u]\)。后者是容易的;对于前者,发现只有一段后缀的最优决策不变、其余的最优决策变为了 \([l, u]\) 这个区间的最优决策点,即答案与 \(r\) 成线性关系。我们使用线段树维护,在线段树上二分即可。线段树需要支持区间加 / 赋值一个等差数列。

时间复杂度 \(\mathcal{O}(n \log n)\)

posted @ 2022-10-08 20:08  Scintilla06  阅读(82)  评论(0编辑  收藏  举报