跳至主要內容

ICPC 2021 World Finals 部分题解

Wallbreaker5th大约 7 分钟OI×ICPCOI×ICPCOI×ICPC - 题解OI×ICPC - DFSOI×ICPC - 数论OI×ICPC - 枚举OI×ICPC - 计算几何OI×ICPC - 二分答案OI×ICPC - 贪心OI×ICPC - 排序OI×ICPC - DP - 数据结构优化OI×ICPC - Trie

注意

题解写得可能非常抽象。

「如果一个题解你看不懂,那是题解垃圾而不是你垃圾。」

比赛链接:Codeforces Gymopen in new window

B. Dungeon Crawler

题意

有一棵 nn 个点的树,边有长度,qq 次询问,给定点 s,k,ts,k,t,分别代表起点、钥匙所在的点、陷阱所在的点。你要从起点出发,用尽量短的时间遍历过所有点,但要求到达陷阱点之前必须经过过钥匙点。n2000,q2×105n\leq 2000, q\leq 2 \times 10^5。5 s。

题解

每次询问 O(n)O(n) 求解(可以通过提前计算 DFS 序、避免递归等减小常数)。

显然,答案应当是选择一个最深的叶子 ll,将其作为最后到达的点,从而它到根的链上的边只用经过一次,而其他边需要两次。但如果这个点在 lca(k,t)\operatorname{lca}(k,t)kk 所在的字数中就有问题了,因为这个子树不能简单地放到最后访问。我们需要:

  • lca(k,t)\operatorname{lca}(k,t) 外面的点,先正常遍历完。
  • lca(k,t)\operatorname{lca}(k,t) 时,先进 kk 所在的子树,把整棵子树遍历完,但是在 lca(k,l)\operatorname{lca}(k,l) 处,不往 ll 所在的子树里面走。
  • 回到 lca(k,t)\operatorname{lca}(k,t),遍历其他所有子树。
  • 再回到 lca(k,t)\operatorname{lca}(k,t),走到 lca(k,l)\operatorname{lca}(k,l),遍历 ll 所在的子树,并最后停在 ll

注意到从 lca(k,t)\operatorname{lca}(k,t)lca(k,l)\operatorname{lca}(k,l) 的部分一共会经过三次。求解是为了方便,可以直接在计算深度时,把 kklca(k,t)\operatorname{lca}(k,t) 这一部分边的权值当做负的,代表它们反而会使答案增加一倍边权。

C. Fair Division

题意

nn 个人分 mm 块钱。他们要先确定一个数 0<f<10<f<1,第一个人拿走 mm 块钱的 ff 倍,第二个人拿走剩下的钱的 ff 倍,……,第 nn 个人拿走剩下的钱的 ff 倍,第一个人拿走剩下的钱的 ff 倍……最后每个人都会拿到一个收敛的钱数。求 ff 使得每个人拿到的钱数都是整数或判断无解。优先最小化 ff 的分母,其次最小化 ff 的分子。6n106,m10186\leq n\leq 10^6, m\leq 10^18

题解

1f=a/b1-f = a/b(a,b)=1(a,b)=1,则每个人拿的钱是 fk/(1(a/b)n)mf^k/(1-(a/b)^n) m,简单通分和因式分解后,要求为 (an1+an2b++bn1)m(a^{n-1} + a^{n-2}b + \cdots + b^{n-1})|mbb 不可能很大,枚举即可。

F. Islands from the Sky

题意

平面上有 nn 个多边形,每个 nkn_k 个点。现在希望从空中拍摄这些多边形。有 mm 条航线,每条是空间中的一个线段;飞机沿航线飞行时会使用相机拍照,拍摄范围为底边与航线垂直、整体与地面垂直、顶点为飞机位置、顶点角度为 2θ2 \theta 的等腰三角形,对应到平面上是一个线段;飞行一段之后扫过的即为一个等腰梯形。求 θ\theta 至少是多少,才能保证每个多边形都至少被一条航线完全拍摄到,或者判断无解。n,m,ni100n,m,n_i\leq 100

题解

二分 θ\theta。多边形被一条航线完全拍摄到等价于每个顶点都被这条航线拍摄到;判断时只需要求出这个点在【线段在平面上投影】的投影位置的比例(从而求出对应的飞机高度,从而求出扫过范围的宽度),以及这个点到【线段在平面上投影】的距离。

H. Prehistoric Programs

题意

nn 个小括号构成的字符串,求一个方案,将其拼接成一个合法括号序列,或者判断无解。字符串长度和 10710^7

题解

考虑左括号为 +1+1,右括号为 1-1,则每个串要求前缀和不小于一个数,如果满足就可以接上它并让和加上另一个数。这是经典的「如果血量不小于 XXX 就可以打怪,打怪可以获得 XXX 血量」的问题。排序,净加分为正的排在前面,负的排在后面;对于正的,右括号少的排在前面;对于负的,左括号多的排在前面。排完序之后检查一遍。

I. Spider Walk

题意

有一个蜘蛛网,nn 条从中心向外的射线,mm 条两节相邻射线上(相同模长)的点的边;每条边对应的模长各不相同。蜘蛛从中心出发,沿着射线 ss 向外走,遇到边就爬过去,这样最终会到达某条射线。对于每条射线 ii,求从 ss 出发,要最终到达 ii,至少要添加多少条边。n2×105,m5×105n\leq 2\times 10^5, m\leq 5\times 10^5

题解

考虑从内往外,一边考虑每条边,一边维护每根射线的需要边数,这个边数的差分一定是 0,1,10,-1,1。遇到一条边,会将两条射线的需要边数交换,然后每条射线要和相邻射线边数加一取 min\min,注意到这个操作至多改变 O(1)O(1) 处边的差分,找到修改位置需要求某点开始向左/右最长的差分全 1-1/11 的延伸距离。用 set 维护哪些差分是 00、是 11、是 1-1,最后得到差分数组后,从答案是 00 的射线开始推即可还原出答案。往集合里面同时放 i,in,i+ni,i-n,i+n 可以简化实现。

J. Splitstream

题意

nn 个序列处理机,共两种:

  • 输入两个序列,一左一右地取,归并成一个新序列,输出。
  • 输入一个序列,一左一右地分配到两个序列,输出。

这些处理机接起来,每个输出至多用作一次输入。有一个初始序列 aa11mm 可能多次用作输入。多次询问某份输出的第 kk 个元素。n104,m109,q103n\leq 10^4, m\leq 10^9, q\leq 10^3

题解

序列的长度一定在 nmnm 以内。先预处理出每个序列的长度。每次询问都 O(n)O(n) 处理:拿到询问之后,你就知道它是哪个输入序列里的第几个了,从而可以往前追溯,直到到达 11(或者输出 1-1)。

L. Where Am I?

题意

有一个 n×mn\times m 的网格,每个格子是黑色或白色,网格外的格子都是白色。格子除了颜色外没有不同。现在考虑从 (i,j)(i,j) 格出发,按一个一开始向上、逆时针的螺旋取遍历整个平面;我知道网格的样子,但不知道自己的初始位置,因此只能通过格子的黑白判断自己的位置,考虑最早知道自己位置的时刻。考虑对于网格内的所有格子,求这个时刻的平均值、最大值、取到最大值的初始格子。n,m100n,m\leq 100,黑色格子数不超过 100100

题解

一个想法是把每个点作为起点,经过的格子黑白情况建出 Trie,但会有 nmnmnmnm 级别的串,不能通过。但黑色格子数很少,我们转而把每个黑色格子的到达时刻作为一个串,将这个串建 Trie。每个叶子结点被识别出来的时间为:找到它的第一个有分叉的祖先,如果连向它所在子树的边的字符是最大的一个,时刻为次大的边的字符,否则就为这条边的字符。由此可以容易求出最大值、平均值。

写题解的时候发现,是不是对字符串排个序,然后通过判断相邻的字符串的 LCP 就可以求出每个串最早被识别出来的时刻了。