ICPC 2021 World Finals 部分题解
注意
题解写得可能非常抽象。
「如果一个题解你看不懂,那是题解垃圾而不是你垃圾。」
比赛链接:Codeforces Gym
B. Dungeon Crawler
题意
有一棵 个点的树,边有长度, 次询问,给定点 ,分别代表起点、钥匙所在的点、陷阱所在的点。你要从起点出发,用尽量短的时间遍历过所有点,但要求到达陷阱点之前必须经过过钥匙点。。5 s。
题解
每次询问 求解(可以通过提前计算 DFS 序、避免递归等减小常数)。
显然,答案应当是选择一个最深的叶子 ,将其作为最后到达的点,从而它到根的链上的边只用经过一次,而其他边需要两次。但如果这个点在 的 所在的字数中就有问题了,因为这个子树不能简单地放到最后访问。我们需要:
- 外面的点,先正常遍历完。
- 到 时,先进 所在的子树,把整棵子树遍历完,但是在 处,不往 所在的子树里面走。
- 回到 ,遍历其他所有子树。
- 再回到 ,走到 ,遍历 所在的子树,并最后停在 。
注意到从 到 的部分一共会经过三次。求解是为了方便,可以直接在计算深度时,把 到 这一部分边的权值当做负的,代表它们反而会使答案增加一倍边权。
C. Fair Division
题意
个人分 块钱。他们要先确定一个数 ,第一个人拿走 块钱的 倍,第二个人拿走剩下的钱的 倍,……,第 个人拿走剩下的钱的 倍,第一个人拿走剩下的钱的 倍……最后每个人都会拿到一个收敛的钱数。求 使得每个人拿到的钱数都是整数或判断无解。优先最小化 的分母,其次最小化 的分子。。
题解
设 且 ,则每个人拿的钱是 ,简单通分和因式分解后,要求为 。 不可能很大,枚举即可。
F. Islands from the Sky
题意
平面上有 个多边形,每个 个点。现在希望从空中拍摄这些多边形。有 条航线,每条是空间中的一个线段;飞机沿航线飞行时会使用相机拍照,拍摄范围为底边与航线垂直、整体与地面垂直、顶点为飞机位置、顶点角度为 的等腰三角形,对应到平面上是一个线段;飞行一段之后扫过的即为一个等腰梯形。求 至少是多少,才能保证每个多边形都至少被一条航线完全拍摄到,或者判断无解。
题解
二分 。多边形被一条航线完全拍摄到等价于每个顶点都被这条航线拍摄到;判断时只需要求出这个点在【线段在平面上投影】的投影位置的比例(从而求出对应的飞机高度,从而求出扫过范围的宽度),以及这个点到【线段在平面上投影】的距离。
H. Prehistoric Programs
题意
有 个小括号构成的字符串,求一个方案,将其拼接成一个合法括号序列,或者判断无解。字符串长度和 。
题解
考虑左括号为 ,右括号为 ,则每个串要求前缀和不小于一个数,如果满足就可以接上它并让和加上另一个数。这是经典的「如果血量不小于 XXX 就可以打怪,打怪可以获得 XXX 血量」的问题。排序,净加分为正的排在前面,负的排在后面;对于正的,右括号少的排在前面;对于负的,左括号多的排在前面。排完序之后检查一遍。
I. Spider Walk
题意
有一个蜘蛛网, 条从中心向外的射线, 条两节相邻射线上(相同模长)的点的边;每条边对应的模长各不相同。蜘蛛从中心出发,沿着射线 向外走,遇到边就爬过去,这样最终会到达某条射线。对于每条射线 ,求从 出发,要最终到达 ,至少要添加多少条边。。
题解
考虑从内往外,一边考虑每条边,一边维护每根射线的需要边数,这个边数的差分一定是 。遇到一条边,会将两条射线的需要边数交换,然后每条射线要和相邻射线边数加一取 ,注意到这个操作至多改变 处边的差分,找到修改位置需要求某点开始向左/右最长的差分全 / 的延伸距离。用 set
维护哪些差分是 、是 、是 ,最后得到差分数组后,从答案是 的射线开始推即可还原出答案。往集合里面同时放 可以简化实现。
J. Splitstream
题意
有 个序列处理机,共两种:
- 输入两个序列,一左一右地取,归并成一个新序列,输出。
- 输入一个序列,一左一右地分配到两个序列,输出。
这些处理机接起来,每个输出至多用作一次输入。有一个初始序列 为 到 可能多次用作输入。多次询问某份输出的第 个元素。。
题解
序列的长度一定在 以内。先预处理出每个序列的长度。每次询问都 处理:拿到询问之后,你就知道它是哪个输入序列里的第几个了,从而可以往前追溯,直到到达 (或者输出 )。
L. Where Am I?
题意
有一个 的网格,每个格子是黑色或白色,网格外的格子都是白色。格子除了颜色外没有不同。现在考虑从 格出发,按一个一开始向上、逆时针的螺旋取遍历整个平面;我知道网格的样子,但不知道自己的初始位置,因此只能通过格子的黑白判断自己的位置,考虑最早知道自己位置的时刻。考虑对于网格内的所有格子,求这个时刻的平均值、最大值、取到最大值的初始格子。,黑色格子数不超过 。
题解
一个想法是把每个点作为起点,经过的格子黑白情况建出 Trie,但会有 个 级别的串,不能通过。但黑色格子数很少,我们转而把每个黑色格子的到达时刻作为一个串,将这个串建 Trie。每个叶子结点被识别出来的时间为:找到它的第一个有分叉的祖先,如果连向它所在子树的边的字符是最大的一个,时刻为次大的边的字符,否则就为这条边的字符。由此可以容易求出最大值、平均值。
写题解的时候发现,是不是对字符串排个序,然后通过判断相邻的字符串的 LCP 就可以求出每个串最早被识别出来的时刻了。