AtCoder ARC194 题解

AtCoder ARC194 题解

前言

前四题时自己通过的,最后一题题解写得很清楚,就很快通过了。

A - Operations on a Stack

发现如果操作序列是 add-add-del-del 那么可以转化为 add-del-add-del,它们的贡献是一样的。

即我们现在有两种操作:选择 \(a_i\);跳过 \(a_i,a_{i+1}\),贡献为 \(0\)。那么设 \(f_i\) 表示考虑完前 \(i\) 个位置的最大贡献,转移为:

\[f_i+a_{i+1}\to f_{i+1} \]

\[f_i\to f_{i+2} \]

复杂度 \(O(n)\)。

B - Minimum Cost Sort

考虑到由于代价与位置有关,那么我们有一种贪心的策略「先尽量在前面交换,之后再在后面交换」,然后我就想到一种策略:

从前往后扫一遍,前面扫过的所有数已经排好序了,然后将当前扫到的数不断交换插入其中使得有序。

那么用一个树状数组维护比它大的个数即可,交上去发现它过了。这里没开 long long 罚了一发。

复杂度 \(O(n\log n)\),证明未知。

C - Cost to Flip

首先对于 \(0\to 0\) 的不用管。而对于 \(0\to 1\) 和 \(1\to 0\) 可以想到排序后先做 \(1\to 0\),再做 \(0\to 1\),这样是最优的。证明考虑一对先做 \(0\to 1\),再做 \(1\to 0\),交换它们一定更优。

而发现还有一种情况,即 \(1\to 1\),我们可以在开始 \(1\to 0\),再在结尾 \(0\to 1\),这转化成了上述两种情况。我们可以选择一些 \(1\to 1\) 执行这个策略,并且我们发现一定是从大往小执行这个策略。

那么我们用树状数组维护两个序列,分别是 \(0\to 1\) 和 \(1\to 0\),需要维护后缀值域个数以及前缀值域和。枚举执行 \(1\to 1\) 策略的前缀,往树状数组里插入和查询即可实时维护答案。

复杂度 \(O(n\log n)\)。

D - Reverse Brackets

首先考虑把括号序变成树状结构,排序以后二分加递归即可。

由于每一括号序都唯一对应一棵树,那么答案就是对每个节点可以重排儿子,问有多少种树的形态。

设 \(f_i\) 表示以 \(i\) 为子树的树形态个数。那么设与儿子 \(j\) 形态相同的儿子子树共 \(cnt\) 种,当前已经考虑完了 \(c\) 个儿子,有转移:

\[f_i\gets f_i\times f_j^{cnt}\times \binom {c+cnt} {cnt} \]

使用树哈希或者括号序用来判断形态相同的儿子子树,复杂度 \(O(n\log n)\) 或 \(O(n^2\log n)\)。

代码用树哈希被卡了,用 string 存括号序就过了。

E - Swap 0^X and 1^Y

题解做法:先判掉 01 个数不等。考虑把连续的 \(c\) 个 0 变成 \(\lfloor \frac c X\rfloor\) 个 A,\(c\bmod X\) 个 0。对于 1 同理,变成 B 和 1。

下文中的 \(S,T\) 均为完成上述操作后的 \(S,T\)。原题就变成了,交换 \(S\) 中相邻的 0A,1B,AB 后使 \(S\) 变为 \(T\)。

考虑将 \(S\) 和 \(T\) 经过下列操作直到不能操作,变成 \(S'\) 和 \(T'\)。

  • 子串 A0 交换。
  • 子串 1B 交换。
  • 子串 AB 交换。

如果 \(S'=T'\) 则 \(S\) 可变为 \(T\)。那么现在考虑 \(S'=T'\) 的充要。

只要考虑如下三个序列:01 构成的子序列,所有相邻 1 之间 A 的个数,所有相邻 0 之间 B 的个数。

如果 \(S,T\) 的上述三个序列都相等,则 \(S'=T'\)。

证明首先考虑 01 的子序列是不能交换的,然后 1 之间的 A 全部只能放在 1 之前,0 之间的 B 全部只能放在 0 之后。

时间复杂度 \(O(n)\)。

posted @ 2025-03-11 22:12  dengchengyu  阅读(332)  评论(0)    收藏  举报