題目
題解
枚舉左括號,計算它左邊都是左括號右邊都是右括號的複合要求的個數。
當枚舉到一個左括號時設此左括號的左邊有 \(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;
}