题目链接:Codeforces-785D-Anton and School - 2
每当扫描到一个左括号时,设这个左括号必选,左边有
a
个左括号(包括其本身),右边有
∑min(a−1,b−1)i=0Cia−1Ci+1b=∑min(a−1,b−1)i=0Ca−(i+1)a−1Ci+1b=Cb−1a+b−1=∑min(a,b)i=0Ca−ia−1Cib=Caa+b−1
因此,无论求和的上标取
a
还是
因此可以
O(nlog(mod))
预处理出阶乘和阶乘的逆元,然后
O(n)
算出答案。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=2e5+7;
const ll mod=1e9+7;
ll fac[maxn],inv[maxn];
ll QMult(ll a, ll b)
{
ll c=1;
while(b)
{
if(b&1) c=c*a%mod;
a=a*a%mod;
b>>=1;
}
return c;
}
void init()
{
fac[0]=inv[0]=1;
for(ll i=1;i<maxn;i++)
{
fac[i]=fac[i-1]*i%mod;
inv[i]=QMult(fac[i],mod-2);
}
}
ll C(ll m, ll n)
{
return fac[n]*inv[n-m]%mod*inv[m]%mod;
}
int main()
{
ios::sync_with_stdio(false);
init();
string s;
cin>>s;
int r=0,l=0;
for(int i=0;i<s.length();i++)
if(s[i]==')') r++;
ll ans=0;
for(int i=0;i<s.length();i++)
{
if(s[i]=='(') l++;
else r--;
if(s[i]=='(') ans=(ans+C(l,l+r-1))%mod;
}
cout << ans << endl;
return 0;
}