Codeforces Round 1073 Div.1 做题记录
Codeforces Round 1073 Div.1
| 编号 | CF2190 |
|---|---|
| 赛时解决 | A,B1 |
| 赛后订题 | A,B1,B2,C |
Solution
A
容易发现这个游戏的结束状态是唯一的,也就是所有 0 都在 1 的前面。
所以一开始就处在结束状态的话 Bob 获胜,直接判掉,接下来看 Alice。
注意到 Alice 只需要对以下两种位置操作:
- a. 处在【结束状态为 1】位置上的 0.
- b. 处在【结束状态为 0】位置上的 1.
而所有 a 情况都在 b 情况前面,因此对它们操作就能一次赢下游戏。
B1
别想复杂了。
手玩之后会发现 )(( 这个结构很优秀,因为 \(t\) 只需要在 \(s\) 的基础上扣掉 ) 和 ((也就是它左右两边的)就行了,并且答案取到上界 \(n-2\)。
所以只需要判是否包含 )(( 这个子序列即可,会发现如果上述条件成立,那么必定存在 )( 这个子串后面存在一个 (,这样也可以。
简单证一下这样得到的 \(t\) 是合法的括号串。我们下文视为删掉的 ) 和 ( 中间存在一个 (,下文提到的括号指代的均为删掉的括号。
- 对于
)前面的位置,没有影响。 - 对于
)后面的位置,由于)的删除,前缀和会增加 \(1\)。又因为这一段本来前缀和是 \(\ge 0\) 的,现在变为 \(\ge 1\)。 - 对于
(后面的位置,由于(的删除,前缀和会减少 \(1\)。又因为这一段被上述情况包含,本来前缀和是 \(\ge 1\) 的,现在变为 \(\ge 0\),依然合法。
B2
发现 \(n \le 100\),大力 DP。
根据上面的结论,我们要统计的是包含子序列 )(( 的所有子序列的贡献之和。
而贡献是和子序列长度相关的,最简单的思路是直接入下标,不过这样的话状态 \(O(n^3)\) 时间 \(O(n^4)\),直接爆炸。
考虑长度能不能转换一下,反正求的是贡献之和,不如直接求长度之和。
但是贡献是 \(n-2\) 的,还需要对每个长度 \(-2\)。那就在开个 DP 数组,统计满足条件的子序列个数而不是长度就可以了。
状态数 \(O(n^2)\),时间 \(O(n^3)\),可以通过本题!
C
交互。题意很简单,有一个排列 \(p\),允许 \(3n\) 次询问,每次询问是任意两个位置的大小关系。
需要还原出来一个字典序最小的排列 \(q\),使得 \(q > p\) 且 \(rev(q) > rev(p)\)。给出排列 \(r\) 有 \(q_i = p_{r_i}\) 即可。
会发现排列 \(q\) 前一段和 \(p\) 相同,然后在某个位置上更大,最后单调递增。
考虑这个形式,字典序最小的时候 LCP 一定最长,那么考虑怎么找到这个最长的东西。
换而言之,我们需要找到最长的 LCP,使得去掉这部分后后面依旧有解。
思考什么时候无解,容易发现先递减后递增(或纯递减纯递增)是唯一的无解情况。
那么我们只需要从后往前找到这样无解的一段,然后向前扩张一个就是最短的有解情况了。
现在我们确定出 \([1,p)\) 为 LCP,考虑让 \((p,n]\) 中比 \(p\) 位置大的数中的最小值来替换 \(p\)。
我们根据后面部分的性质(即先递减后递增)来找即可,注意根据分割点左右讨论取最优值,擂台法。
替换完了之后就是两段的归并了,总的次数 \(3n\)。其实替换 \(p\) 也可以二分的,不过没必要吧。

浙公网安备 33010602011771号