「题解」Codeforces 785D

题目

CF785D

题解

枚举左括号,计算它左边都是左括号右边都是右括号的复合要求的个数。

当枚举到一个左括号时设此左括号的左边有 \(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;
}
posted @ 2021-10-21 11:09  yu__xuan  阅读(56)  评论(4编辑  收藏  举报