CF1709C Recover an RBS
题意
共 组数据,每组给定一个字符串 ,包括 (, ) 和 ?。你可以进行无限次操作,每次把一个 ? 换成一个 ( 或者一个 )。问是否有多种方法可以将这个字符串变为一个正确的括号序列。
解法
考虑贪心。
对于每一个字符串,我们不妨先找到其中一个正确的括号序列。假设最初这个字符串长度为 ,其中有 个 (, 个 )。那么我们要将 个 ? 替换成 (,把 个 ? 替换成 )。
显然当一个字符串是一个括号序列时,对于每一位 ,从 到 中 ( 的出现次数一定 ) 出现的次数。并且最终 ( 和 ) 出现次数一样。
我们不妨找到 ? 变成 ( 的所有字符中最靠后的一个和 ? 变成 ) 最靠前的一个。交换这两个 ( 和 )。如果交换后这是一个合法括号序列,那么至少有两种合法方案,如果不合法,则只有一种合法方案。
接下来考虑证明:
假设找到的两个位置为 和 。反证,如果有另一个合法序列,交换了 和 ,显然不存在 或 ,因为 和 都是端点。那么一定有 和 。显然对于 到 和 到 而言,与交换 没有区别对于中间的括号,由于 和 的范围比 和 大,显然选取较小的范围也一定可以。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
using namespace std;
int t;
string s;
inline bool check(string p)
{
int c1 = 0, c2 = 0, l = p.size() - 1;
for (int i = 0; i <= l; i++)
{
c1 += p[i] == '(';
c2 += p[i] == ')';
if (c1 < c2) return 0;
}
if (c1 != c2) return 0;
return 1;
}
int main()
{
ios::sync_with_stdio(false), cin.tie(nullptr), cout.tie(nullptr);
cin >> t;
while (t--)
{
cin >> s;
int l = s.size() - 1;
int c1 = count(s.begin(), s.end(), '('), c2 = count(s.begin(), s.end(), ')');
string copy = s;
int pl = 0, pr = 0;
for (int i = 0; i <= l; i++)
{
if (copy[i] == '?' && c1 + 1 <= (l + 1) / 2) copy[i] = '(', c1++, pl = i;
else if (copy[i] == '?')
{
copy[i] = ')', c2++;
if (!pr) pr = i;
}
}
string h = copy;
swap(copy[pl], copy[pr]);
if (h != copy && check(copy))
{
printf("NO\n");
}
else printf("YES\n");
}
return 0;
}

浙公网安备 33010602011771号