题目大意

给定一个括号序列
可以删除某一些括号
使得该序列成为一个
长度为偶数
前n/2为 “(”
后n/2为“)”
的匹配括号串
问删除的方案数

题目分析

枚举作为最后一个( 的 符号,计算以这个符号为节点的方案数
前缀和算出该符号之前的 ( 个数, 后缀和算出该符号右边的)个数
由于,当前符号必须选中
所以,想到于在之前的符号中选取 i个,之后的符号中选取i+1个
令x = l[i] 表示左边的左括号个数
y=r[i] 表示右边的有括号个数

当前 符号的方案数 C(x,i)*C(y,i+1)的求和
然后通过范德蒙恒等式转换一下就好啦

代码详解

#include <bits/stdc++.h>
#define cl(a) memset(a,0,sizeof(a))
#define sc(x) scanf("%d",&x)
#define pt(x) printf("%d\n",x)
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define per(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int maxn=2e5+50;
const int mod=1e9+7;
const int inf=0x3f3f3f3f;
typedef long long ll;
ll fpow(ll n,ll k,ll p=mod){ll r=1;for(;k;k>>=1){if(k&1)r = r*n%p;n=n*n%p;}return r;}
ll inv(ll n,ll p=mod){return fpow(n,p-2,p);}
ll n,m;
ll fact[maxn];
void init()
{
    fact[0]=1;
    for(int i=1;i<maxn;i++)
        fact[i]=fact[i-1]*i%mod;
}
ll C(ll n, ll m)
{
    ll t = fact[n]*inv(fact[m])%mod;
       t = t * inv(fact[n-m])%mod;
    return t;
}
ll l[maxn],r[maxn];
int main()
{

    ios::sync_with_stdio(false);
    cin.tie(0);
    string s;
    cin>>s;
    ll ans=0;
    init();
  // for(int i=1;i<10;i++) cout<<fact[i]<<" ";
    for(int i=0;i<s.size();i++)
    {
        l[i]=l[i-1];
        if(s[i]=='(') l[i]++;
    }
    for(int i=s.size()-1;i>=0;i--)
    {
        r[i]=r[i+1];
        if(s[i]==')')r[i]++;
    }
    for(int i=0;i<s.size();i++)
    {
        if(s[i]=='(')
        {
            // int t= min(l[i],r[i]);
             ans=(ans+C(l[i]+r[i]-1,l[i]))%mod;
        }
    }
    cout<<ans<<endl;
    return 0;
}