codeforces 785D D. Anton and School

题目链接:http://codeforces.com/problemset/problem/785/D

题意:给你一个只包含'('和')'的字符串,然后问他的子序列中有多少满足前一半是左括号,后一半是右括号。

分析:看到题就想到是组合数学,对于一个左括号,他能影响到的右括号就是他后边的,因此,你需要求前缀和和后缀和,来这样来求组合数。现在我们枚举左括号,当枚举到他时,代表他一定被选,前缀和为n,后缀和为m,然后在他前边选i=0到min(n,m)-1个,在他后边选前边数+1个。然后就是C(n-1,i)*C(m,i+1) ,也就是C(n-1,i)+C(m,m-i-1);求和即为C(n+m-1,m-1),然后用卢卡斯定理求即可,注意存n!还有求逆元。

AC代码:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 long long mod=1e9+7;
 5 char s[200005];
 6 int a[200005];
 7 int b[200005];
 8 long long num[200005];
 9 long long qpow(long long x,long long n){
10     if(n==0) return 1;
11     long long ans=1;
12     x=x%mod;
13     while(n!=0){
14         if(n&1) {
15             ans=ans*x%mod;
16         }
17         x=x*x%mod;
18         n=n/2;
19     }
20     return ans;
21 }
22 long long Cn(long long n,long long m){
23     if(n<m) return 0;
24     if(n==m) return 1;
25     if(m>n-m) m=n-m;
26 
27     return (num[n]*qpow(num[n-m]*num[m],mod-2))%mod;
28 }
29 
30 int main(){
31     ios_base::sync_with_stdio(0);
32     cin.tie(0);
33     num[0]=1;
34     for(long long i=1;i<=200000;i++){
35         num[i]=num[i-1]*i%mod;
36     }
37     cin>>s;
38     int d=strlen(s);
39     int num1=0,num2=0;
40     for(int i=0;i<d;i++){
41         if(s[i]=='('){
42             num1++;
43         }
44         a[i]=num1;
45     }
46     for(int i=d-1;i>=0;i--){
47         if(s[i]==')'){
48             num2++;
49         }
50         b[i]=num2;
51     }
52     long long result=0;
53     for(int i=0;i<d;i++){
54         if(s[i]=='('){
55            result=(result+Cn(a[i]+b[i]-1,b[i]-1))%mod;
56         //cout<<result<<endl;
57         }
58     }
59     cout<<result<<endl;
60     return 0;
61 }
View Code
原文地址:https://www.cnblogs.com/ls961006/p/6947669.html