「题解」Codeforces 785D
题目
题解
枚举左括号,计算它左边都是左括号右边都是右括号的复合要求的个数。
当枚举到一个左括号时设此左括号的左边有 \(n\) 个左括号,右边有 \(m\) 个右括号则要算的是 \(\sum\limits_{i = 0}^{\min(n,m - 1)}C_{n}^{i}C_{m}^{i + 1}\)。
总的复杂度为 \(O(n^2logP)\) 不太行。
观察这个式子。
\(\large\sum\limits_{i = 0}^{\min(n,m - 1)}C_{n}^{i}C_{m}^{i + 1} = \large\sum\limits_{i = 0}^{\min(n,m - 1)}C_{n}^{n - i}C_{m}^{i + 1} = \large C_{n+m}^{n+1}\)
中间那个式子和 \(C_{n}^{n}C_{m}^{1} + C_{n}^{n - 1}C_{m}^{2} + \dots + C_{n}^{n-\min(n,m-1)}C_{m}^{\min(n,m-1)+1}\) 等价,考虑一下他的实际意义其实就是把 \(n+m\) 个数分成左边 \(n\) 个数,右边 \(m\) 个数,从里面选择 \(n + 1\) 个数,是和 \(C_{n+m}^{n+1}\) 等价的。
总复杂度为 \(O(nlogP)\)
Code
#include <cstdio>
#include <cstring>
#include <string>
#include <iostream>
#include <algorithm>
#define M 200002
typedef long long ll;
int min(int a, int b) { return a < b ? a : b; }
int max(int a, int b) { return a > b ? a : b; }
inline void read(int &T) {
int x = 0; bool f = 0; char c = getchar();
while (c < '0' || c > '9') { if (c == '-') f = !f; c = getchar(); }
while (c >= '0' && c <= '9') { x = x * 10 + c - '0'; c = getchar(); }
T = f ? -x : x;
}
std::string s;
const int mod = 1e9 + 7;
int n, ans, jc[M], sum0[M], sum1[M];
int qpow(int a, int b) {
int ans = 1, base = a;
while (b) {
if (b & 1) ans = 1ll * ans * 1ll * base % mod;
base = 1ll * base * 1ll * base % mod;
b >>= 1;
}
return ans % mod;
}
int main() {
std::cin >> s; n = s.length(), jc[0] = 1, ans = 0;
for (int i = 1; i <= n; ++i) jc[i] = 1ll * jc[i - 1] * 1ll * i % mod;
for (int i = 0; i < n; ++i) {
sum0[i + 1] = sum0[i];
sum1[i + 1] = sum1[i];
if (s[i] == '(') ++sum0[i + 1];
else ++sum1[i + 1];
}
for (int i = 0; i < n; ++i) {
if (s[i] == '(') {
int res = 1ll * jc[sum0[i] + sum1[n] - sum1[i + 1]] * 1ll * qpow(1ll * jc[sum0[i] + 1] * 1ll * jc[sum1[n] - sum1[i + 1] - 1] % mod, mod - 2) % mod;
ans = (1ll * ans + 1ll * res) % mod;
}
}
std::cout << ans << '\n';
return 0;
}