CF1709C Recover an RBS

题意

tt 组数据,每组给定一个字符串 ss,包括 ()?。你可以进行无限次操作,每次把一个 ? 换成一个 ( 或者一个 )。问是否有多种方法可以将这个字符串变为一个正确的括号序列。

解法

考虑贪心。

对于每一个字符串,我们不妨先找到其中一个正确的括号序列。假设最初这个字符串长度为 nn,其中有 xx(yy)。那么我们要将 n2x\dfrac{n}{2} - x? 替换成 (,把 n2y\dfrac{n}{2} - y? 替换成 )

显然当一个字符串是一个括号序列时,对于每一位 ii,从 11ii( 的出现次数一定 \geq ) 出现的次数。并且最终 () 出现次数一样。

我们不妨找到 ? 变成 ( 的所有字符中最靠后的一个和 ? 变成 ) 最靠前的一个。交换这两个 ()。如果交换后这是一个合法括号序列,那么至少有两种合法方案,如果不合法,则只有一种合法方案。

接下来考虑证明:

假设找到的两个位置为 iijj。反证,如果有另一个合法序列,交换了 xxyy,显然不存在 x>ix > iy<jy < j,因为 iijj 都是端点。那么一定有 xix \leq iyjy \geq j。显然对于 11x1x - 1y+1y + 1nn 而言,与交换 i,ji, j 没有区别对于中间的括号,由于 xxyy 的范围比 iijj 大,显然选取较小的范围也一定可以。

代码:

#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;
}
posted @   HappyBobb  阅读(4)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示