Official

D - Count Bracket Sequences Editorial by en_translator


1. Properties of parenthesis string

A string \(S\) consisting of ( and ) is a parenthesis string if and only if the following two conditions are satisfied.

  • For all \(i\), the first \(i\) characters of \(S\) contains more occurrences of ( than of )
  • \(S\) contains the same number of ( and ).

This can be shown by induction on the length of \(S\).

2. Counting

Let \(dp_{i,j}\) be the number of ways to replace each occurrence of ? with ( or ) in the first \(i\) characters, such that ( occurs more than ) in the first \(k\) characters for all \(k \leq i\), and (the number of (s in the first \(i\) characters) \(-\) (the number of )s in the first \(i\) characters) \( = j\). What we want is \(dp_{N,0}\).

We describe the transitions of the DP (Dynamic Programming). If each ? in the first \((i-1)\) characters is replaced with ( and ), and (the number of (s in the first \((i-1)\) characters) \(-\) (the number of )s in the first \((i-1)\) characters) \(= j\), then (the number of (s in the first \(i\) characters) \(-\) (the number of )s in the first \(i\) characters) becomes \(j+1\) if \(S_i = \) (, \(j-1\) if \(S_i = \) ), and \(j+1\) and \(j-1\) if \(S_i = \) ? is replaced with ( and ), respectively.

Therefore, the transition is as follows: if \(S_i =\) (, then add \(dp_{i,j}\) to \(dp_{i+1,j+1}\); if \(S_i =\) ), then add it to \(dp_{i+1,j-1}\); if \(S_i =\) ?, then add it to \(dp_{i+1,j+1}\) and \(dp_{i+1,j+1}\).

Since there are \(O(N^2)\) states in the DP, and each transition costs \(O(1)\), so the problem has been solved in a total of \(O(N^2)\) time.

Sample code

#include <iostream>
#include <string>
#include <vector>
#include <atcoder/modint>
using namespace std;
using mint = atcoder::static_modint<998244353>;

int main() {
	string s;
	cin >> s;
	int n = s.size();
	vector<vector<mint>> dp(n + 1, vector<mint>(n + 1));
	dp[0][0] = 1;
	for (int i = 0; i < n; i++) {
		for (int j = 0; j < n; j++) {
			if (s[i] != ')') dp[i + 1][j + 1] += dp[i][j];
			if (j != 0 && s[i] != '(') dp[i + 1][j - 1] += dp[i][j];
		}
	}
	cout << dp[n][0].val() << '\n';
}

posted:
last update: