简单的括号序列
自我感觉是一个签到题,但是想了很久,最后求助才能苟活。
按照它的定义,很容易想到如何求出合法的序列:
当我们确定一个右括号时,假设它左边有 \(a\) 个左括号,右边有 \(b\) 个右括号,那么我们可以从 \(a\) 中选出 \(i\) 个,从 \(b\) 中选出 \(i - 1\) 个,即可组成一个合法的序列。
所以现在答案变成了,对于每个右括号:
\[\sum^{i\leq min (a-1,b)}_{i=0} \binom{a}{i+1} \binom{b}{i}
\]
但是我们现在只能是 \(\Theta(n^2)\) 的复杂度,考虑将式子化简。
式子的本质含义是从 \(a\) 集合中选 \(i+1\) 个,从 \(b\) 集合中选 \(i\) 个,由:
\[\binom{b}{i} = \binom{b}{b - i}
\]
可得,问题又转化成了 \(a\) 集合中选 \(i+1\) 个,从 \(b\) 集合中选 \(b-i\) 个,那直接将 \(a,b\) 集合合并,直接转化成从 \(a+b\) 中选 \(b+1\) 个:
\[\binom{a+b}{b+1}
\]
莫得了...
代码
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
typedef long long ll;
using namespace std;
const int maxn = 4e5 + 50, INF = 0x3f3f3f3f, mod = 1e9 + 7;
inline int read () {
register int x = 0, w = 1;
register char ch = getchar ();
for (; ch < '0' || ch > '9'; ch = getchar ()) if (ch == '-') w = -1;
for (; ch >= '0' && ch <= '9'; ch = getchar ()) x = x * 10 + ch - '0';
return x * w;
}
inline void write (register int x) {
if (x / 10) write (x / 10);
putchar (x % 10 + '0');
}
int n, sumf[maxn], sumb[maxn];
char str[maxn];
ll ans, fac[maxn], facinv[maxn];
inline ll qpow (register ll a, register ll b) {
register ll ans = 1;
while (b) {
if (b & 1) ans = ans * a % mod;
a = a * a % mod, b >>= 1;
}
return ans;
}
inline void Init () {
fac[0] = 1;
for (register int i = 1; i <= 4e5; i ++) fac[i] = fac[i - 1] * i % mod;
facinv[400000] = qpow (fac[400000], mod - 2);
for (register int i = 4e5; i >= 1; i --) facinv[i - 1] = facinv[i] * i % mod;
}
inline ll C (register int a, register int b) {
if (a == 0 || b == 0 || a == b) return 1;
if (a < b) return 0;
return fac[a] * facinv[b] % mod * facinv[a - b] % mod;
}
int main () {
scanf ("%s", str + 1), n = strlen (str + 1), Init ();
register int tmp = 0;
for (register int i = 1; i <= n; i ++) {
if (str[i] == '(') tmp ++;
else sumf[i] = tmp;
}
tmp = 0;
for (register int i = n; i >= 1; i --) {
if (str[i] == ')') sumb[i] = tmp, tmp ++;
}
for (register int i = 1; i <= n; i ++) {
if (str[i] == '(') continue;
ans = (ans + C (sumf[i] + sumb[i], sumb[i] + 1)) % mod;
}
printf ("%lld\n", ans);
return 0;
}