codeforces 785D D. Anton and School - 2
阿新 • • 發佈:2017-06-06
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&1View Code) { 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 }
codeforces 785D D. Anton and School - 2