CodeForces 785D Anton and School - 2 组合数学

题意:

给你一串括号 问你有多少种匹配的子串

就是前半部分都是'(' 后半部分都是')'的子串

 

思路:

首先我们预处理

当前位置之前有多少左括号 和 当前位置之后有多少右括号

 

对于每一个处于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 */

 

转载于:https://www.cnblogs.com/general10/p/7224626.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值