【括号匹配】

【括号匹配】

题目整理

Ghost in the Parentheses

https://ac.nowcoder.com/acm/contest/108301/G

题目大意

image

思路

【本题关键】

(1)将'('看成+1 ')'看成-1:做前缀和找规律
->可发现合法的括号序列所有的前缀和一定是非负的
->选一个(和一个)对调 会使区间前缀和-2
->可发现若一个*合法*的序列 存在点的前缀和sum[i]<=1:这两个点不能对调 否则序列不合法
(2)如何得出唯一?->需要打表【这种很可能出性质】
考虑(((...))):只能在中间打问号

->

对于一个(,找到右边最近的*合法*位置,然后构造唯一:((...))的形式

代码

int n;
string s;
void solve(){
    cin>>s;
    n=s.size();
    s=' '+s;
    vector<i64> f(n+1,0);
    //预处理2的幂次
    f[0]=1LL;
    for(int i=1;i<=n;i++){
        f[i]=f[i-1]*2LL%mod;
    }
    i64 inv2=qmi(2LL,mod-2,mod);
    vector<int> sum(n+1,0);
    for(int i=1;i<=n;i++){
        sum[i]=sum[i-1]+(s[i]=='('?1:-1);
    }
    vector<int> pre(n+2,0),suf(n+2,0);//统计1~i左括号 i~n右括号
    for(int i=1;i<=n;i++){
        pre[i]=pre[i-1]+(s[i]=='(');
    }
    for(int i=n;i>=1;i--){
        suf[i]=suf[i+1]+(s[i]==')');
    }
    int r=1;
    i64 ans=0;
    for(int i=1;i<=n;i++){
        r=max(r,i);//往右边找
        //找<=1的点
        while(r<=n && sum[r]>1) r++;
        if(s[i]=='('){
            //i和r这两个括号对调是不合法的,因此不能打问号 
            //i-1之前和r+1之后的括号也不能打问号
            ans=(ans+f[pre[i-1]]*f[suf[r+1]]%mod)%mod;
        }
    }
    //原序列是一个有效解:(((???或者???))) 所以*n/2
    ans=(ans+f[n/2])%mod;
    for(int i=1;i<=n;i++) ans=ans*inv2%mod;
    cout<<ans<<endl;
}
posted @ 2025-07-25 00:53  White_ink  阅读(22)  评论(0)    收藏  举报