给定一个长度为 n 的括号序列 s,其中的第 i 个字符 si 要么是 (
,要么是 )
。
现在,你需要选择其中一个括号字符,并改变其括号类型((
变为 )
,)
变为 (
)。
请你计算,有多少个位置 i 满足,将 si 的括号类型改变后,得到的新括号序列是一个合法括号序列。
如果新括号序列 s 同时满足:
- s 中
(
和)
的数量相同。 - 对于 s 的任意前缀字符串,其中包含的
(
的数量均不少于)
的数量。
则新括号序列是一个合法括号序列。
输入格式
第一行包含整数 n。
第二行包含一个长度为 n 的由 (
和 )
组成的字符串。
输出格式
一个整数,表示满足条件的位置数量。
数据范围
前四个测试点满足 1≤n≤10。
所有测试点满足 1≤n≤106。
输入样例1:
6
(((())
输出样例1:
3
输入样例2:
6
()()()
输出样例2:
0
输入样例3:
1
)
输出样例3:
0
输入样例4:
8
)))(((((
输出样例4:
0
分析:
我正序遍历了前i中(的个数a[i],倒序了i及其右边(的个数b[i],又用st[i]表示从开头到现在中是否有不合法的现象,st1[i]表示从结尾到i处是否有不合法的现象,同时如果(和)的个数相差不为2或者n为奇数均可直接写0,其他的在判断第i个能不能替换时,先判断该符号替换后会不会不满足第一个情况,再判断是否满足第二种情况,再判断该店前后是否均合法即可,若都满足,则ans++;
代码如下:
#include <bits/stdc++.h>
using namespace std;
const int N=1e6+10;
int a[N],st[N],b[N],st1[N];
char c[N];
int n,ans;
int main()
{
cin>>n;
for(int i=1;i<=n;i++)cin>>c[i];
if(n%2)
{
cout<<0;
return 0;
}
for(int i=1;i<=n;i++)
{
if(c[i]=='(')a[i]=a[i-1]+1;
else a[i]=a[i-1];
if(a[i]<i-a[i])st[i]=1;
st[i]=max(st[i],st[i-1]);
}
for(int i=n;i;i--)
{
if(c[i]=='(')b[i]=b[i+1]+1;
else b[i]=b[i+1];
if(b[i]>n-i+1-b[i])st1[i]=1;
st1[i]=max(st1[i],st1[i+1]);
}
if(abs(n-a[n]*2)!=2)
{
cout<<0;
return 0;
}
int flag=0;
if(n-a[n]*2==-2) flag=1;
for(int i=1;i<=n;i++)
{
if(flag&&c[i]==')')continue;
if(!flag&&c[i]=='(')continue;
if(c[i]=='('&&i-a[i]+1>a[i]-1)continue;
if(c[i]==')'&&i-a[i]-1>a[i]+1)continue;
if(st[i-1]||st1[i+1])continue;
ans++;
}
cout<<ans;
return 0;
}