题意:
给你一串括号 问你有多少种匹配的子串
就是前半部分都是‘(‘ 后半部分都是‘)‘的子串
思路:
首先我们预处理
当前位置之前有多少左括号 和 当前位置之后有多少右括号
对于每一个处于i位置的左括号
我们将ans+=C(left[i]+right[i]-1,right[i]-1)
这个式子是C(i-1,left[i]-1)*C(i+1,right[i])化简来的
因为选的数总数是不变的 所以可以化简(?)
就是从左边选i-1个左括号 从右边选i+1个右括号
因为自己是必选的 所以左括号-1
1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a)) 3 #define debug(a) cerr<<#a<<"=="<<a<<endl 4 using namespace std; 5 typedef long long ll; 6 typedef pair<int,int> pii; 7 8 const int maxn=2e5+10; 9 const int mod=1e9+7; 10 11 ll fac[maxn]; 12 13 ll quick_pow(ll a,ll n) 14 { 15 ll ans=1; 16 while(n) 17 { 18 if(n%2) ans=1ll*ans*a%mod; 19 a=1ll*a*a%mod; 20 n>>=1; 21 } 22 return ans; 23 } 24 25 ll inv(ll a) 26 { 27 return quick_pow(a,mod-2); 28 } 29 30 void init() 31 { 32 fac[0]=1; 33 for(int i=1;i<maxn;i++) 34 { 35 fac[i]=1ll*fac[i-1]*i%mod; 36 } 37 } 38 39 ll C(ll a,ll b) 40 { 41 ll ans=1; 42 if(a<b || b<0) return 0; 43 while(a&&b) 44 { 45 ll aa=a%mod,bb=b%mod; 46 if(aa<bb) return 0;; 47 ans = 1ll*ans*fac[aa]%mod * inv(1ll*fac[bb]*fac[aa-bb]%mod)%mod; 48 a/=mod,b/=mod; 49 } 50 return ans; 51 } 52 53 int main() 54 { 55 string str; 56 cin>>str; 57 int sz=str.size(); 58 vector<int>left(sz,0),right(sz,0); 59 if(str[0]==‘(‘) left[0]=1; 60 for(int i=1;i<sz;i++) 61 { 62 left[i]=left[i-1]+(str[i]==‘(‘); 63 } 64 if(str[sz-1]==‘)‘) right[sz-1]=1; 65 for(int i=sz-2;i>=0;i--) 66 { 67 right[i]=right[i+1]+(str[i]==‘)‘); 68 } 69 ll ans=0; 70 init(); 71 for(int i=0;i<sz;i++) 72 { 73 if(str[i]==‘(‘) 74 { 75 ans+=C(left[i]+right[i]-1,right[i]-1); 76 ans%=mod; 77 } 78 } 79 cout<<ans<<endl; 80 return 0; 81 }/* 82 83 )(()() 84 85 */
时间: 2024-10-11 21:28:21