【2023上海大学春季赛】J. Juxtaposed brackets | 栈

标题链接

Problem – J – Codeforces

标题

递归界说集合 BB 如下:

(1)()∈B()\in B

(2) 若x,y∈Bx,y\in B,则 (x),(xy)∈B(x),(xy)\in B

给定一个非空字符串SS,其间 SS 只由两种字符()组成。

请你回答这个字符串是否属于 BB

【2023上海大学春季赛】J. Juxtaposed brackets

标题大意

如标题描绘所示。

思路

首要咱们发现 BB 中的元素一定是匹配的括号序列,能够先用栈将非法的括号序列排查出去。

然后咱们观察到标题中说到:

x,y∈Bx,y\in B,则 (x),(xy)∈B(x),(xy)\in B

这就告诉咱们一个事实,即:

x,y,z∈Bx,y,z\in B,则 (xyz)∉B(xyz)\notin B

咱们利用括号的包括关系建树,假设 a,b,ca,b,c 均为合法的括号序列,若 aa 直接包括 bb,即 a=(b)a=(b) 或者 a=(bc)a=(bc),就使 aa 成为 bb 的父节点。

在这种规则下,BB 中元素发生的树一定是一个连通的二叉树。并且由集合 BB 的界说,一个连通的二叉树对应的括号序列一定是 BB 的子集。

那么具体怎样建树呢?

咱们首要记载给每个括号取一个姓名,并在左右括号都加以记载。每当咱们遇到一个左括号 ii 时,假如 ii 的左面紧挨着一个左括号,那么他是 ii 的父节点;假如 ii 的左面紧挨着一个右括号,那么他是 ii 的兄弟节点,他的父节点是 ii 的父节点。

完结建树后,咱们只需要判别整棵树是否连通、每个节点的子节点数量是否大于 22 即可。

为了方便的判别树是否连通,我使得全场第一个左括号以 00 作为其父节点,这样的话只需要判别 00 的子节点数量是否是 11 即可判别整棵树是否连通。

代码

#include <bits/stdc++.h>
using namespace std;
const int N=300005;
char a[N];
int n,flag,id[N],bel[N],stk[N],t,tot,cnt[N];
int solve()
{
	for (int i=0;i<=n;++i) bel[i]=0,cnt[i]=0;
	scanf(" %s",a+1);
	n=strlen(a+1);
	flag=1;
	t=tot=0;
	for (int i=1;i<=n;++i)
	{
		if (a[i]=='(') id[i]=stk[++t]=++tot;
		else
		{
			if (t<1) return 0;
			id[i]=stk[t--];
		}
	}
	if (t!=0) return 0;
	for (int i=2;i<=n;++i)
	{
		if (a[i]!='(') continue;
		if (a[i-1]=='(') cnt[bel[id[i]]=id[i-1]]++;
		else cnt[bel[id[i]]=bel[id[i-1]]]++;
	}
	if (cnt[0]) return 0;
	for (int i=1;i<=n;++i)
		if (cnt[i]>2) return 0;
	return 1;
}
int main()
{
	int T;
	for (scanf("%d",&T);T--;) 
		if (solve()) printf("YES\n");
		else printf("NO\n");
	return 0;
}