4430. 括号序列

给定一个长度为 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值