算是寒假的第一把 cf,被这道题意极其绕的两个题困扰了许久,遂写题解记录思考过程。
D1. Sub-RBS (Easy Version)
意外的是,赛时写出的代码竟然与官解思路是一模一样的。但其实发现还可以转化成一个更强的结论,这也是能够做出 D2 的关键。
我的做法是:只需要固定原序列的某个以右括号结尾的前缀,并将结尾的右括号替换成其右侧最近的左括号(替换的是选择的位置)。这样,这个右括号被替换成了左括号,剩余的前一部分和原前缀相同,正好满足了题目描述的 better 条件。那么我们接下来就只需要尽可能扩大剩余的选择长度,使得选择的子序列是 RBS 即可。
容易发现,在 “将结尾的右括号替换成其右侧最近的左括号” 这一过程中,我们跳过的全部都是右括号,而 RBS 要求左右括号数量相同。那么我们可以猜想:是不是剩余部分有足够的左括号供我们跳过,其他部分全选,形成的就一定是 RBS 了?赛时并没有继续深入思考这一点,而是勇了一把直接猜结论,正好猜对了。事实上也可以证明出来一定是这样:
首先需要明确 RBS 的定义:将左括号当作 \(1\),右括号当作 \(-1\),求该括号串的前缀和 \(pre\)。那么一个括号串是 \(RBS\),当且仅当:
- 末尾项 \(pre\) 等于 \(0\)
- 前缀所有位置的 \(pre \geq 0\)
显然,我们去除的是等量的左右括号,最终子序列的 \(pre\) 值一定仍然为 \(0\);且在去除括号序列在顺序上满足:所有右括号均在左侧,所有左括号均在右侧。那么贪心地思考,前缀所有位置的 \(pre\) 显然仍是非负的。因此,上述两个条件都满足,形成的子序列一定是 \(RBS\),证毕。
综上,我们只需要枚举所有原序列中以右括号结尾的前缀,计算该情况下可选出的最长 RBS,所有情况取最大值就可以了。具体实现见代码。
code
D2. Sub-RBS (Hard Version)
继续思考 D1 有没有什么更强的结论存在:我们发现,若每次选择的是 紧右侧是'(' 的 ')',那么跳过的 ')' 数量就会减少,进而剩余部分需要跳过的 '(' 数量也会减少,那么条件就会更加宽松;并且这样做还能扩大答案的长度,何乐而不为呢?于是,我们会发现:
- 若有解,则答案一定是 \(n-2\)
- 原序列中的子序列 \(t\) better,当且仅当 \(t\) 是一个 RBS ,并且在 \(t\) 中存在 “)(”,并且其右侧存在 '(' (进一步思考,其实就是存在子序列 ")(("(不一定连续),因为只有'(' ')'两种字符)
其中第二个条件就是衡量子序列价值的一个关键条件,必须要发掘到,要不然 D2 就会特别难想。
D2 要求原序列的所有子序列的总价值之和,而每个子序列价值经过我们上述处理变为了一个非常清晰的特征。于是我们可以考虑如何 \(dp\) 了。
\(dp\) 过程直接贴官解了,写得非常清晰易懂:

code