IOI2022 Day1 题解
vp 是五小时零几分钟 AK 。考虑到一学期没训了,就假装自己 AK 了吧。
IOI Day1 怎么才四个 AK
T1 1h 左右就过了,但是对着 T2 降智了很久。幸好 30min 会了 T3 ,可惜就这么一点代码量还是花了 1h 才调过去。
LOJ#3830. 「IOI2022」鲶鱼塘
不难发现连续的长堤应当是先上升再下降的,并且最高的高度是 \(n\) 。
因此一段连续的长堤能抓到的鱼也是先上升再下降。
那就直接设 \(dp_{i,0/1}\) 表示目前的最后一条鱼是第 \(i\) 条,且现在在上升/下降,此时的最大值。然后朝着同一列或下一列的这个方向转移。
注意特殊处理高度为 \(n\) 和高度为 \(0\) 的长堤。
LOJ#3831. 「IOI2022」囚徒挑战
警告:这里写的是个垃圾做法。
思路非常简单,就是把 \(A\) 和 \(B\) 都写成三进制,然后从上到下比较。
作为一个成熟的 OIer ,你应该一眼看出一个 \(1+3\lceil \log_3 n\rceil\) 的做法。不像我,在开始的一个多小时都以为要 \(4\) 个点才能把 \(n\) 除掉 \(3\) 。
就是对于三进制的每一位都分配三个点,并且奇数位分配给 \(A\) ,偶数位分配给 \(B\) 。那么进来一个人就可以搞定一位。
然后观察样例,在 \(n=3\) 时竟然只需要 \(1+1\) 个点而非 \(1+3\) 个点。不难发现这是因为在 \(A\) 处进行了掐头去尾的操作,所以每次不是 \(n\to n/3\) ,而是 \(n\to (n-2)/3\) 。加上这个优化就可以卡进 \(21\) 个点了。
不过这也给实现带来了一些麻烦。在朴素实现里,每次只需要比较 \(A\bmod 3^k\) 和 \(B\bmod 3^k\) ,但是现在则没有这么好的形式。
我使用了比较简单粗暴(但也不太好写)的并查集维护等价类做法。把 \([1,n]\) 拆分成 \(k+2\) 个集合 \(S_0,S_1,\cdots,S_k,S_{k+1}\) ,设 \(id(x)\) 表示 \(x\) 所在的集合编号,那么就是要比较 \(id(A)\) 和 \(id(B)\) 。并且如果现在看的是 \(B\) 那么会保证 \(id(A)\in [1,k]\) ,看 \(A\) 时同理。那么判掉 \(id(B)\in \{0,1,k,k+1\}\) 之后就可以把剩下的集合切成三个序列,把对应位置合并,再丢到对面去,就可以使得等价类个数除掉 \(3\) 。
(这里写的很不清楚,但我的做法确实就是这么烂。)
LOJ#3832. 「IOI2022」无线电信号塔
因为这题只用了 30min 就会了,所以我没有被 hhz 偏序!
显然有一个贪心:每次从最大值的位置切开,如果左边存在信号塔可以通过它通讯就把左边区间的答案加起来,右边同理。如果两边都没有就返回 \(1\) 。
建出笛卡尔树,那么在一个区间会因为两边都没有而返回 \(1\) 当且仅当子树内所有信号塔都不能通过自己通讯,但存在一个信号塔能通过父亲通讯。答案就是这样的区间的个数,并且不难发现这些区间两两无交(即在笛卡尔树上没有祖先关系)。
不难发现,即使一次询问不是询问整个序列,在整个笛卡尔树上贪心仍然是正确的,只是要把“信号塔”替换为“在询问区间内的信号塔”。
因此我们不妨先对每个位置处理出询问区间是 \([1,n]\) 时哪些 \(D\) 是合法的(这显然也组成了一个区间),然后再把不需要的贡献减掉。
对一个位置 \(x\) ,设 \([l_x,r_x]\) 表示它在笛卡尔树上的区间。设 \([l,r]\) 表示询问区间。那么我们可以把 \(x\) 分成 \(6\) 种:
- \(l_x\le l\le r\le r_x\)
- \(r_x<l\)
- \(l_x>r\)
- \(l\le l_x\le r_x\le r\)
- \(l_x<l\le r_x\le r\)
- \(l\le l_x\le r<r_x\)
第 \(1,5,6\) 种在笛卡尔树上形成了 \(O(1)\) 条链,直接减即可;第 \(2,3\) 种也只需要用主席树处理;第 \(4\) 种则完全不需要处理。
减掉了不需要的贡献之后,再把需要的贡献加上。
第 \(1,5,6\) 种形成了 \(O(1)\) 条链,因此有贡献的点也只有 \(O(1)\) 个(前面说过有贡献的点两两没有祖先关系) ,直接倍增即可;第 \(2,3,4\) 种没有额外贡献。
所以总复杂度 \(O(n\log n)\) 。