Romanian Master of Informatics 2020 题解
罗马尼亚大师赛。
感觉题目挺有趣的。
Day 1
A \(\color{green}\bigstar\)
通信,要询问区间最大值,那么压缩笛卡尔树即可。
考虑笛卡尔树的建树过程,加入点就加入一个 1
,删除就放一个 0
,就可以还原了。
一颗二叉树都可以这样压缩。
想了一下其他压缩方式,设 \(s_{l,r}\) 表示区间 \([l,r]\) 压缩出的串,那么设 \(t\) 表示区间最大值。
这样也唯一对应括号序列。
B \(\color{Gold}\bigstar\)
有很多比较阴间的 bitset、FFT 做法,但是正解很高妙。
先观察一下变换的性质,设 \(f_{i,k}\) 表示 \(i\) ,在位数为 \(k\) 的时候进行翻转得到的东西是什么。
可以得到 \(f_{i,k+1}=2f_{i,k},f_{i+2^{k},k+1}=2f_{i,k}+1\)
考虑哈希。
朴素的一个区间的哈希就是 \(\sum B^{n-i}a_i\),\(B\) 是一个常数。
套在这个上面,发现就是把 \(f_{i,k}\) 的每一个 \(B^i\) 变成 \(B^{2i}\),然后后面的多乘一个 \(B\)。
直接维护平方很不好维护,此时很妙的一手是开始设置一个 \(P=B^{2^c}\),开始先让所有 \(f_{i,0}\) 乘上 \(P\),然后每次转移只需要把 \(P\) 开个根号,这样就可以支持两个合并了。
那么同理,前面的前缀和预处理也要对每个空隙大小跑一遍,然后就可以判断了。
复杂度 \(O(n\log n)\)。
C \(\color{Gold}\bigstar\)
高妙数据结构科技。
首先 \(O(n\log n)\) 有若干做法,不说了。
然后注意到维护这个 dp,要维护一个前面删除,后面加入删除,还要支持全局查询最小值。
很牛的一个科技是双栈模拟,每个栈记录一个前缀最小值,然后直接合并。
一个栈如果弹空了,那么把另一个栈分一半过来。
复杂度分析的话记录势能为两个栈大小的绝对值,复杂度就是 \(O(n)\)。
Day 2
A \(\color{blue}\bigstar\)
空间 20mb。。。
显然建个树,然后跑个祖先。
一开始写了个 dfs ,然后栈上二分,MLE。
学习了空间复杂度 \(O(n)\) 的树上倍增,有点太牛了。
就是如果大跳两步距离一样就合并,证明一下复杂度是对的,严格吊打树剖。