【括号匹配】
【括号匹配】
题目整理
Ghost in the Parentheses
https://ac.nowcoder.com/acm/contest/108301/G
题目大意
思路
【本题关键】
(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;
}