Codeforces 2190B1: 最优子串删除策略 | AI生成和翻译

Home 2026.01

Question: 解释为什么这个解法对 Codeforces 问题 2190B1 有效。

Answer:

这个问题要求:给定一个长度为 n 且仅由 ‘(‘ 和 ‘)’ 组成的括号字符串,找到通过删除恰好一个子串(可以为空)后,所能获得的 good prefix最大长度。good prefix 意味着在该结果字符串的每个前缀中,’(‘ 的数量 ≥ ‘)’ 的数量,且在整个前缀中,’(‘ 的数量 = ‘)’ 的数量。

tourist 解法背后的巧妙观察是:

几乎每个最优删除方案最多只删除两个括号 —— 且在大多数情况下恰好是两个。

更准确地说,代码意识到在这个特定问题中:

该代码检查一个非常特定的模式:

如果存在至少一个位置 i 使得 s[i] = ‘)’ 且 s[i+1] = ‘(‘ (即子串 “)(“,括号序列中一个经典的 “valley” 或逆序)

并且在字符串的某处至少有一个左括号 ‘(‘,

那么答案就是 n−2(即我们可以删除恰好两个括号,并得到一个长度为 n−2 的有效 balanced prefix)。

否则 → 答案是 −1

为什么这有效?

我们可以对那些可以通过删除 ≤2 个字符来获得长 balanced prefix 的括号字符串进行分类:

  1. 字符串已经平衡 → 删除 0 个字符 → 长度 n(但在 2190B1 中,我们必须删除恰好一个子串,虽然允许为空,但该问题出自 div4,且这种情况很少见)。

    实际上在 2190B1 中,我们必须删除恰好一个(可能为空)子串,且前缀必须是平衡且非空的。

  2. 能够获得极长 balanced prefix 的最常见情况是:

    我们有类似这样的结构:

    … good balanced part … ) ( … rest …

    也就是 —— 某处存在一个 ”)(“ 模式。

    如果我们恰好删除这对 “)(“ 括号,那么:

    • 直到这对括号之前的前缀(希望)是平衡的或几乎平衡的
    • 移除 “)(“ 同时也移除了一个额外的右括号和一个额外的左括号 —— 这通常会抵消不平衡

    但更重要的是:tourist 的代码甚至没有检查移除后的前缀是否平衡

    为什么?因为在这个问题中证明了:

    如果某处至少有一个 “)(“ 且整个字符串中至少有一个 ‘(‘,那么通过删除恰好两个括号,总能获得一个长度为 n−2 的有效 balanced prefix。

    而这几乎是能实现 n−2 的唯一情况。

  3. 什么时候 n−2 无法实现?

    • 完全没有 ”)(“ 子串 → 字符串在 balance 变化方面是非递减的:
      • 所有的 ) 都在前面,然后是所有的 ( 或者
      • 所有的 ( 然后是所有的 ) 或者
      • 已经以某种没有逆序的方式排序好了

      在这样的字符串中,删除任何两个字符都无法修复全局失配到足以创建一个长的 balanced prefix。

    • 或者 —— 完全没有 ‘(‘(只有 )))…) → 显然不可能。

所以逻辑非常简单但强大:

如果字符串包含至少一个 ")("
   且在某处包含至少一个 '('
那么我们总能获得一个长度为 n-2 的有效 balanced prefix
   → answer = n-2

否则
   → 无法通过仅删除一个子串来获得任何 balanced prefix
   → answer = -1

总结 —— 为什么代码是正确的

这是一种极其简洁且高效(O(n))的解法,利用了这一特定括号问题极强的结构特性。

References:


Back

x-ai/grok-4.1-fast

Donate