http://codeforces.com/problemset/problem/785/D
题目大意:
长度为偶数
左侧全为 '('
右侧全为 ')'
左右长度相同
问满足上述条件的子序列有多少种选法
分析:
首先 范德蒙恒等式
枚举分界线 每一个分界线记录其左侧 '(' 数量和右侧 ')' 数量(包含本身)
从左到右 每遇到一个 '(' 时 当前 '(' 必选 则其贡献值为 然后根据范德蒙恒等式可得 (以上两图来自QuanQqqqq的博客)
AC代码:
#include <iostream>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <vector>
#include <stack>
#include <queue>
#include <map>
#include <set>
#include<list>
#include <bitset>
#include <climits>
#include <algorithm>
#define gcd(a,b) __gcd(a,b)
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w",stdout)
typedef long long LL;
const LL mod=1e9+7;
const int INF=0x3f3f3f3f;
const double PI=acos(-1.0);
using namespace std;
struct node{
int l;
int r;
}a[2000005];
char str[2000005];
LL fac[2000005];
LL Power(LL a,LL b){
LL temp=1;
while (b){
if(b%2)
temp=(temp*a)%mod;
b/=2;
a=a*a%mod;
}
return temp%mod;
}
void fun(){
fac[0]=1;
fac[1]=1;
for (int i=2;i<=2000000;i++){
fac[i]=fac[i-1]*i%mod;
}
}
LL cal(LL n,LL m){
return fac[n]*Power(fac[n-m],mod-2)%mod*Power(fac[m],mod-2)%mod;
}
int main (){
// FIN;
fun();
while (scanf("%s",str+1)!=EOF){
int n=strlen(str+1);
memset(a,0,sizeof(a));
for (int i=1;i<=n;i++){
if (str[i]=='(')
a[i].l=a[i-1].l+1;
else
a[i].l=a[i-1].l;
}
for (int i=n;i>=1;i--){
if (str[i]==')')
a[i].r=a[i+1].r+1;
else
a[i].r=a[i+1].r;
}
LL ans=0;
for (int i=1;i<=n;i++){
if (str[i]=='('){
ans+=cal(a[i].l+a[i].r,a[i].r);
}
}
printf ("%lld\n",ans%mod);
}
return 0;
}