ICPC World Finals 2021 部分题解
H.史前程序
签到题,可能因为比较典?
令左括号为 \(1\),右括号为 \(-1\)。\(a_i\) 为每个串的 \(\operatorname{sum}\),\(b_i\) 为前缀 \(\min\)。
先判一下 \(\sum a_i\) 是否等于 \(0\),首先把 \(a_i\ge0\) 的拿出来,因为 \(a_i<0\) 的 \(b_i\) 也 \(<0\)。
这部分按照 \(b_i\) 从大到小排序,考虑假如非法了,调换顺序没用。
剩下的反着考虑(从后往前加),发现 \(b_i\leftarrow b_i-a_i,a_i\leftarrow-a_i\) 规约成和上面一样的问题。
B.地下城探测者
钥匙为 \(k\),陷阱为 \(t\)。
以起点为根考虑问题。先判掉 \(t\) 是 \(k\) 祖先的情况。
把整棵树完整绕一圈回到原点的代价是 \(2\) 倍边权和,如果没有这一堆限制,减去最大深度即可。
到了 \(k\) 之后,必须要先离开走到 \(t\) 那里(有可能要先走完 \(t\) 的子树)。
令 \(l=\operatorname{LCA}(k,t)\)。如果最后停留的点不在 \(l\) 的子树内,那不会带来额外的贡献。
否则考虑和 \((l,k)\) 这条链相交的长度,讨论一下发现带来的贡献是 \(\operatorname{len}\times2\)。
写法很多,我是维护了子树内不同儿子能延伸的长度的最大值和次大值。
讨论很容易错漏。
I.蛛网漫游
显然是从远到近加入 bridge,考虑一个 strand 作为端点时有两种情况:
-
直接让答案等于另一端的答案
-
另一端的答案不如其它地方走过来更新
自然想到同时维护所有答案。
暴力的话就开一个数组,最初 \(s=0\),其它都是 \(\inf\)。
每次先 check 一遍有没有相邻的 \(x,y\) 满足 \(a_x+1<a_y\),把 \(a_y\leftarrow a_x+1\)。
加入一个 bridge 就直接 \(\operatorname{swap}(a_x,a_y)\)。
感受一下,过程中比较暴力的地方是更新一段公差为 \(\pm1\) 的等差数列。
只要优化了这个显然每次 check 是 \(O(1)\) 的。考虑使用 set 维护连续段。
嘴巴起来很快乐,写起来一车细节。
我写的时候 set 里就存了左端点,公差和首项扔到数组里。
每次看相邻两个段是否能更新,先判断相交的地方差是否大于 \(1\),之后大讨论两边的公差,注意如果整段修改但没有合并的话下次更新要从被修改的地方开始。
具体看代码:https://loj.ac/s/1656315
写的挺丑,不知道线段树是咋维护这东西的。
E.自由标记的手牌
先玩一下第一个样例:
摸牌的方式:\(\binom{28}{4}\),能看到的组合:\(\binom{28}{3}3!\)。发现前者除后者就是答案了。
这大概说明了这两者之间是有完美匹配的!
证明懒得胡了……
此时考虑 tag 这个东西。魔术师也是能看到 \(k\) 张牌 tag 的组合的,所以 tag 组合不同是独立的。
当然直接把概率加起来不对,只需要求出每个组合的摸牌方式数和能看到的组合数。
前者非常显然,后者先枚举一下背面朝上牌的 tag 就行。
枚举 tag 组合直接爆搜。这题场上没几个人过让人很难相信完美匹配这个结论。
J.分流
简单模拟,先拓扑排序求出每个点流量,然后递归找编号。
L.我在哪儿?
先预处理一下路径的形状。
可以在线维护所有等价类,每次只更新有 X 的,需要写一下,代码:https://loj.ac/s/1685934
有一个更简洁的写法,本质上时求每个路径的 LCP,所以把 X 放进去后排个序,LCP 一定在相邻的两者之间,代码:https://loj.ac/s/1685934。
K.带上梗
注意到数据范围后发现直接闵可夫斯基和就能过了,但本质原因还是值域太小,实际上可能性还是指数级的。
但有更好写并且很有趣的做法:
假如知道了最终的方向,那只需要让和这个方向点积的贡献最短就行了。
这下可以直接比大小,一次 DFS。
但是不知道方向,考虑随便钦定方向一定能找到两个凸包上的点(求最大/最小)。
做这两个点所在直线垂线作为方向,如果凸包上还有点一定能找到新的。
复杂度是凸包大小乘 \(n\) 的,主要是凸包内的点找凸包上最远点只能遍历一遍。

浙公网安备 33010602011771号