这题第一眼一直觉得是dp,然而到最后他竟然是个数学题2333
考虑暴力,我们枚举一个‘(‘,来求选他的情况下方案数有多少,那么事实上我们就是要在该位置左边选取i个‘(‘,在其右边选取i+1个‘)‘,可以保证不重不漏。暴力的话On统计即可。那么就是要化简组合数的求和。即C(n,i)*C(m,i+1) (0<=i<=min(n,m-1))
我们发现C(m,i+1)=C(m,m-i-1)
而i+(m-i-1)是定值。
也就是说变成了现在前n个数中选i个,再在后m个数中选m-1-i个,那么这其实等价于在这n+m个数字中一次性选出m-1个。
那么答案就是C(m+n,m-1),On扫一遍并计算组合数即可。
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int mod=1e9+7; 4 const int inf=2e5+10; 5 int fast(int x,int y){ 6 int ans=1; 7 while(y){ 8 if(y&1)ans=1ll*ans*x%mod; 9 x=1ll*x*x%mod; 10 y>>=1; 11 } 12 return ans; 13 } 14 int fac[inf]; 15 int C(int x,int y){ 16 return 1ll*fac[x]*fast(fac[y],mod-2)%mod*fast(fac[x-y],mod-2)%mod; 17 } 18 int n,ans; 19 char s[inf]; 20 int s1[inf],s2[inf]; 21 int main() 22 { 23 scanf("%s",s+1); 24 n=strlen(s+1); 25 fac[0]=1; 26 for(int i=1;i<=n;i++) 27 fac[i]=1ll*fac[i-1]*i%mod; 28 for(int i=1;i<=n;i++) 29 s1[i]=s1[i-1]+(s[i]==‘(‘); 30 for(int i=n;i>=1;i--) 31 s2[i]=s2[i+1]+(s[i]==‘)‘); 32 for(int i=1;i<=n;i++) 33 if(s[i]==‘(‘){ 34 ans+=C(s1[i-1]+s2[i+1],s2[i+1]-1); 35 ans%=mod; 36 } 37 printf("%d\n",ans); 38 return 0; 39 }
事实上这个就是"范德蒙恒等式"