「題解」Codeforces 785D
阿新 • • 發佈:2021-10-21
題目
題解
列舉左括號,計算它左邊都是左括號右邊都是右括號的複合要求的個數。
當列舉到一個左括號時設此左括號的左邊有 \(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; }