给定一个只包含
(
和)
的括号序列,求形如(())
、((()))
,的子序列总数。答案取模。
\(n \leq 2 \times 10 ^ 5\)
\(O(n ^ 2)\) 的暴力显然,关键是如何计算组合数。枚举最后一个 (
,设左边还有 \(x\) 个 (
,右边有 \(y\) 个 )
,则答案为
关键是中间的那一步变形,发现下面两个数字之和为定制 \(x + 1\) ,那么这个式子的含义就可以解读为在 \(x + y\) 个球中选取 \(x + 1\) 个球的方案数,求和符号实际是在枚举在后 \(y\) 个球中选几个。
不会组合数,太逊了。
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int mod = 1000000007;
const int N = 200005;
int fac[N], ifac[N];
string st = "";
int fpow(int x, int k) {
int res = 1;
while (k) {
if (k & 1) res = (long long)res * x % mod;
x = (long long)x * x % mod;
k >>= 1;
}
return res;
}
int calc(int n, int m) {
return (long long)fac[n] * ifac[m] % mod * ifac[n - m] % mod;
}
int main() {
cin >> st;
int len = st.size();
fac[0] = 1;
for (int i = 1; i <= len; i++)
fac[i] = (long long)fac[i - 1] * i % mod;
for (int i = 0; i <= len; i++)
ifac[i] = fpow(fac[i], mod - 2);
int cnt0 = 0, cnt1 = 0;
for (int i = 0; i < len; i++)
cnt1 += (st[i] == ')');
int ans = 0;
for (int i = 0; i < len; i++) {
cnt1 -= (st[i] == ')');
if (st[i] == '(') {
ans = (ans + calc(cnt0 + cnt1, cnt0 + 1)) % mod;
cnt0++;
}
}
printf("%d\n", ans);
return 0;
}
标签:School,CF785D,int,Anton,long,res,fac,binom,mod
From: https://www.cnblogs.com/kirakiraa/p/18083244