消消乐の题解

35pts

考虑直接暴力枚举每一个字段即可。时间复杂度 O(n^3)

50pts

在上面35分的情况下,加上一个栈优化,避免每个子序列都需要进行判断是否可以消除,对于这个做法,我们将时间复杂度降到了 O(n^2)

另外,可以考虑特殊性质A,可以增加10分

100pts

这里分享多种做法:

哈希

由于最大可能会有 2 \times 10^6 个值,对于 1 \times 10^9 或者 998244353 这种模数的话,哈希冲突的概率还是不小,我们可以开到 2^{64} 这样的话我们的哈希区间就达到了 0 - 2^{64} 哈希冲突的概率就很小了。而且还是自然溢出,不需要特意取模。

我们可以使用 unordered_map 来维护这个哈希。计算出每个哈希值出现了多少次, 假设一个哈希值出现了 k 次,那么对答案的贡献就是 c_{k}^{2} 也就是 k \times (k - 1) 个,时间复杂福直接降到了 O(n)

dp

没错,我们的动态规划大人回来了!

考虑 DP,我们用 dp_i 表示以 i 为后缀的合法区间个数。

考虑 dp_i 能由谁转移过来。枚举 j < i,那么假如 dp_i 可以由 dp_j 更新,一定说明区间 [j+1,i] 是“可消除的”。要保证不重不漏,那么 j 一定是 i 前面满足 [j+1,i] 是可消除的最大的位置。

要使得 j 最大,那么 [j+1,i] 一定是以 i 结尾最短的合法区间,令 lst_i = j + 1,那么 [lst_i,i] 就是以 i 结尾最短的可消除区间。所以对于每个 i,有:

dp_i = dp_{lst_i-1} + 1

现在考虑如何找 lst_i

我们假设 dp_i 已经求出,考虑枚举到 i+1 时,dp_{i+1} 应该怎么求。对于 s_{i+1},我们有以下两种情况:

  • s_{lst_i-1} = s_{i+1} 时,把 s_{i+1}s_{lst_i-1} 接在 [lst_i, i] 的两端,合成 [lst_i - 1, i + 1] 一并消除,此时 lst_{i+1} = lst_i - 1

  • s_{lst_i-1} \neq s_{i+1} 时,那么一定是类似于 faabcobf 这样(现在是第二个 f),中间有多个合法区间连在一起,那么我们就考虑以 lst_i - 1 结尾的最小合法区间 [lst_{lst_i-1}, lst_i - 1]。如果 s_{lst_{lst_i-1}} = s_{i+1},那么就可以把 s_{i+1}s_{lst_{lst_i-1}} 并在 [lst_{lst_i-1}, i] 两端一并消除,此时,lst_{i+1} = lst_{lst_{i-1}}。如果 s_{lst_{lst_i-1}} \neq s_{i+1},就再往前跳找 lst_i

1 个赞