题意:
给出一个括号序列,其中有一些地方不知道,用 ? ? ?代替,其余的均为 ( ( (或 ) ) ),可以将 ? ? ?替换为 ( ( (或 ) ) ),是否只有一种替换的方法,是这个序列变成合法的括号序列?合法的括号序列定义为,每一个 ) ) )前都有一个 ( ( (与之匹配,并且这个 ( ( (一旦与某个 ) ) )匹配,他就不能与其他 ) ) )匹配。
tips:
提供一个括号序列合法的检验方法:令 c n t = 0 cnt=0 cnt=0,代表还未完成匹配的左括号,遇到 ( ( (则 c n t cnt cnt++,遇到 ) ) )则 c n t cnt cnt–,在遍历字符串过程中 c n t cnt cnt不能是负数,并且遍历完成后 c n t = = 0 cnt==0 cnt==0。
做法:
先看这个例子 . . . . . . ? ? ) ) ? ? ) ) ? ......??))??))? ......??))??))?,前四个问号一定用来匹配右括号,并且最后一个问号一定是左括号,不然会使 c n t < 0 cnt<0 cnt<0。
( ( ) ) ? ? (())?? (())??,当我们看到第一个问号,这个问号就一定是 ( ( (,因此当我们 w h + c n t = = 1 wh+cnt==1 wh+cnt==1时,也就是匹配完所有不匹配的右括号时,刚好剩一个,这些括号时一定能确定的,在第二个例子就是看到第一个问号,此时无需匹配 ) ) ),并且遇到了第一个 ? ? ?, w h + c n t = 1 + 0 = = 1 wh+cnt=1+0==1 wh+cnt=1+0==1,符合条件,这个时候问号前面的完成匹配,使 c n t = = 0 cnt==0 cnt==0,最后一个问号修改成 ( ( (,使 c n t = = 1 cnt==1 cnt==1,所以当 w h + c n t = = 1 wh+cnt==1 wh+cnt==1时, c n t = 1 , w h = 0 cnt=1,wh=0 cnt=1,wh=0。如此操作,到最后遍历完剩余的问号数和没匹配的括号数(包括左右括号,也就是 ∣ c n t ∣ |cnt| ∣cnt∣)相等时,意味所有问号一定用来匹配这些括号,是唯一的合法序列,反之则是不合法。
#include<bits/stdc++.h>
#define ll long long
using namespace std;
int read()
{
int ret=0,base=1;
char ch=getchar();
while(!isdigit(ch))
{
if(ch=='-') base=-1;
ch=getchar();
}
while(isdigit(ch))
{
ret=(ret<<3)+(ret<<1)+ch-48;
ch=getchar();
}
return ret*base;
}
int n;
char s[200005];
void work()
{
scanf("%s",s+1);n=strlen(s+1);
int wh=0,cnt=0;
for(int i=1;i<=n;i++)
{
if(s[i]=='(') cnt++;
if(s[i]==')') cnt--;
if(s[i]=='?') wh++;
if(cnt+wh==1)
{
cnt=1;
wh=0;
}
}
if(wh==abs(cnt)) cout<<"YES"<<endl;
else cout<<"NO"<<endl;
}
int main()
{
int t=1;
scanf("%d",&t);
while(t--) work();
return 0;
}