1. 程式人生 > >codeforces 785D D. Anton and School - 2

codeforces 785D D. Anton and School - 2

style ems its com -1 return 他能 har pow

題目鏈接: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

codeforces 785D D. Anton and School - 2