Description

给定一个长度为 $ n $ 的小括号序列,求有多少个位置满足将这个位置的括号方向反过来后使得新序列是一个合法的括号序列。即在任意一个位置前缀左括号的个数不少于前缀右括号的个数,同时整个序列左右括号个数相同 $ 1 \leq n \leq 10^6 $

Solution

将左括号记为 \(1\),右括号记为 \(-1\),这个数字序列记为 \(a[]\),它的前缀和记为 \(s[]\),同时记录每一个后缀 \(a[i..n]\) 的最小前缀 \(f[i]\)

计算 \(f[]\) 时,只需要倒序递推即可(类似最大子段和的处理)

如果一个位置 \(i\),满足所有 \(i\) 之前的前缀都合法,且 \(s[n]-2a[i]=0\),并且 \(s[i-1]-a[i]+f[i+1] \ge 0\),则这个位置是满足条件的

#include <bits/stdc++.h>
using namespace std;


#define int long long
const int N = 1000005;

int n,a[N],s[N],f[N];
char c[N];

signed main() {
    ios::sync_with_stdio(false);
    cin>>n>>c+1;
    for(int i=1;i<=n;i++) a[i]=c[i]=='('?1:-1;
    for(int i=1;i<=n;i++) s[i]=s[i-1]+a[i];
    for(int i=n;i>=1;--i) f[i]=min(0ll,f[i+1]+a[i]);
    int ans=0;
    int lim=0,cnt=0;
    for(int i=1;i<=n;i++) {
        cnt+=a[i];
        ++lim;
        if(cnt<0) break;
    }
    for(int i=1;i<=lim;i++) if(s[n]-2*a[i]==0 && s[i-1]-a[i]+f[i+1]>=0) ++ans;
    cout<<ans;
}

相关文章:

  • 2021-10-04
  • 2022-02-09
  • 2021-12-30
  • 2022-01-16
  • 2022-02-06
  • 2021-09-25
  • 2022-12-23
  • 2022-12-23
猜你喜欢
  • 2021-11-14
  • 2022-12-23
  • 2022-12-23
  • 2021-06-04
  • 2022-12-23
  • 2021-11-01
  • 2021-06-05
相关资源
相似解决方案