思路:首先很容易能想到要统计每一个位置的前面有几个'('和后面有几个')',我们先分别用n和m来表示吧。然后我们枚举每个位置,如果当前位置是'('那么答案应该增加sigmaC(n-1,i)+C(m,i+1),可能有人会看不懂,我先解释一下,因为每扫到一个位置是'(',那么增加的部分一定拥有这个位置的'(',所以左边n要-1,右边i要+1。然后这里如果每一个位置都这样求的话,复杂度是O(n²),很明显不行。所以剩下的就是化简组合数了。。讲道理我组合数这么渣还玩这个。。。我们来看下,右边的C(m,i+1)等价于C(m,m-i-1),那么原式=sigmaC(n-1,i)+C(m,m-i-1),我们可以发现取数的和是个定值,为m-1,固等价于sigmaC(n+m-1,m-1),然后再套逆元,这道题就解决了。。。好恶心的题,下面给代码:
#include<iostream>
#include<cmath>
#include<queue>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include<string>
#include<utility>
#include<map>
#define maxn 200005
#define inf 0x3f3f3f3f
using namespace std;
typedef long long LL;
const double eps=1e-8;
#define N 200005
const LL mod=1e9+7;
LL fac[N];
char s[N];
int p,lf[N],rg[N];
void init()
{
int i;
fac[0] =1;
for(i =1; i <= p; i++)
fac[i] = fac[i-1]*i%mod;
}
LL pow(LL a, LL b)
{
LL tmp = a % mod, ans =1;
while(b)
{
if(b &1) ans = ans * tmp % mod;
tmp = tmp*tmp % mod;
b >>=1;
}
return ans;
}
LL C(LL n, LL m)
{
if(m>n||m<0)return 0;
return fac[n]*pow(fac[m]*fac[n-m],mod-2)%mod;
}
int main(){
scanf("%s",s+1);
p=strlen(s+1);
init();
for(int i=1;i<=p;i++){
if(s[i]=='(')
lf[i]=lf[i-1]+1;
else
lf[i]=lf[i-1];
}
for(int i=p;i>0;i--){
if(s[i]==')')
rg[i]=rg[i+1]+1;
else
rg[i]=rg[i+1];
}
LL ans=0;
for(int i=1;i<=p;i++){
if(s[i]=='('){
ans+=C(lf[i]+rg[i]-1,rg[i]-1);
ans%=mod;
}
}
printf("%lld\n",ans);
}