Codeforces785D - Anton and School - 2

传送门

题意

给出一个只包含'(',')'的字符序列,询问有多少个\(RSBS\)

分析

首先需要知道一个公式

\[\sum_{i=0}^{min(x,y)}C_x^i*C_y^i=C_{x+y}^x \]

接下来我们观察第i个'(',假设它左边有x个'(',右边有y个')',那么包含它的RSBS有多少个?答案是\(C_{x+y-1}^x\),因为它已经“消耗了”一个')',所以左边的'('只能与右边的y-1个')'匹配。最后扫一遍即可。

代码

#include<bits/stdc++.h>

const int N = 400010;
const int moder = 1e9 + 7;

int fac[N], inv[N];
char s[N];

int power_mod(int a, int index){
	int ret = 1;
	while (index){
		if (index & 1){
			ret = 1ll * ret * a % moder;
		}
		a = 1ll * a * a % moder;
		index >>= 1;
	}
	return ret;
}

int calc(int x, int y){
	return 1ll * fac[x + y - 1] * inv[y - 1] % moder * inv[x] % moder;
}

void init()
{
    fac[0] = 1;
	for (int i = 1; i < N; ++ i){
		fac[i] = 1ll * fac[i - 1] * i % moder;
	}
	inv[N - 1] = power_mod(fac[N - 1], moder - 2);
	for (int i = N - 2; i >= 0; -- i){
		inv[i] = 1ll * inv[i + 1] * (i + 1) % moder;
	}
}

int main(){
    init();
	scanf("%s", s);
	int cnt2 = 0, len = strlen(s);
	for (int i = 0; i < len; ++ i){
		if (s[i] == ')'){
			++ cnt2;
		}
	}
	int cnt1 = 0, ans = 0;
	for (int i = 0; i < len; ++ i){
		if (s[i] == ')'){
			-- cnt2;
			continue;
		}
		++ cnt1;
		ans = (ans + calc(cnt1, cnt2)) % moder;
	}
	return printf("%d\n", ans), 0;
}

posted @ 2017-03-16 18:55  遗风忘语  阅读(423)  评论(0编辑  收藏  举报