Search for a command to run...
Progressive hints first, then the full explanation and implementation when you're ready to cash out.
Review status
AI-generated and still unreviewed. Double-check the details before internalizing them.
Hints
Open only as much as you need to keep the solve alive.
Only subsequences that are already regular bracket sequences can contribute anything. For such a subsequence , a better regular subsequence cannot have the same length as , because the only length- subsequence is itself.
So for a regular , the best possible positive score is usually . The question becomes: when can deleting exactly one pair of brackets make the result lexicographically better, where beats ?
Look at the first place where the new subsequence differs from . To make it better, some later must slide left into a position that originally contained . That means the deleted characters before that later must include more than .
For a regular sequence, such a deletion of length is possible exactly when the sequence has a return to balance before the end, followed later by another non-empty regular block. In plain terms: must be a concatenation of at least two non-empty regular bracket sequences.
Therefore iff is regular and not primitive; otherwise it is . Now sum this over all subsequences of with a DP that counts regular subsequences by balance and whether balance has already hit after taking at least one pair.
The nasty-looking definition collapses to a much cleaner one:
That is the whole trick. The rest is just counting without doing exponential nonsense.
Call a non-empty regular bracket sequence primitive if its balance is positive at every proper prefix. For example, is primitive, while is not.
First, suppose is regular and non-primitive. Then
where and are both non-empty regular sequences. Let start with and end with its matching closing bracket . Delete exactly those two characters from . The remaining sequence is still regular after being followed by , because removing the outer pair of a primitive component keeps the inside regular.
What happens lexicographically? Before the boundary, the deleted opening bracket eventually causes a later character to shift left. Since returns to balance before , the first actual improvement is that a from the next component can appear where had a . So the new subsequence is better. Its length is , which is the maximum possible positive score because a better subsequence cannot have length .
Now suppose is primitive. Any proper regular subsequence must be shorter than . For to be better, at the first difference it must put where has . That means before this later moved left, the deleted prefix contained more closing brackets than opening brackets. But in a primitive regular sequence, every proper prefix has positive balance. You cannot delete a balanced number of total brackets and already have a prefix deletion with negative balance in the right way without breaking regularity. More concretely: the outer first and last wrap the whole sequence, and any regular subsequence remains trapped inside that outer structure, so it cannot become lexicographically larger than the original wrapper. Primitive sequences contribute .
So we only need to sum over subsequences of that are regular and have already returned to balance before their final character.
We process left to right and build chosen subsequences. A state needs:
Let
store two values for partial subsequences:
Here means the subsequence has had a proper return to balance after being non-empty. Once this happens, if the final balance later becomes , the finished subsequence is non-primitive and contributes.
When reading a character, we can skip it or take it.
If we take , balance increases by .
If we take , balance decreases by , so this is only legal when . After taking it, if the new balance is and the subsequence is not empty, we have just finished a regular block. This should set only if this return to is proper, meaning there will be more chosen characters later. Since we do not know the future, the easiest way is to set a flag whenever a partial subsequence has balance and positive length; later, if we extend it with another , that old zero becomes a proper internal return.
A cleaner implementation uses states:
When adding a to a partial subsequence with balance and positive length, we set , because we just started a second block. That exactly means the final sequence will be non-primitive if it eventually closes.
At the end, every state with balance and represents a regular non-primitive subsequence. Its contribution is
The empty subsequence never contributes; the DP naturally ignores it because it has length and never becomes good.
Complexity is tiny:
per test case, with states per flag. With , this is comfortably inside the limit. No heroics, no black magic, just the right invariant.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct State {
ll cnt = 0;
ll len = 0;
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
string s;
cin >> n >> s;
vector<array<State, 2>> dp(n + 2), ndp;
dp[0][0].cnt = 1; // empty subsequence
for (char c : s) {
ndp = dp;
for (int bal = 0; bal <= n; bal++) {
for (int good = 0; good < 2; good++) {
State cur = dp[bal][good];
if (!cur.cnt) continue;
if (c == '(') {
int ngood = good;
if (bal == 0 && cur.len > 0) ngood = 1;
State &to = ndp[bal + 1][ngood];
to.cnt = (to.cnt + cur.cnt) % MOD;
to.len = (to.len + cur.len + cur.cnt) % MOD;
} else {
if (bal == 0) continue;
State &to = ndp[bal - 1][good];
to.cnt = (to.cnt + cur.cnt) % MOD;
to.len = (to.len + cur.len + cur.cnt) % MOD;
}
}
}
dp.swap(ndp);
}
ll ans = (dp[0][1].len - 2 * dp[0][1].cnt) % MOD;
if (ans < 0) ans += MOD;
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const ll MOD = 998244353;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
struct State {
ll cnt = 0;
ll len = 0;
};
int main() {
setIO();
int T;
cin >> T;
while (T--) {
int n;
string s;
cin >> n >> s;
vector<array<State, 2>> dp(n + 2), ndp;
dp[0][0].cnt = 1; // empty subsequence
for (char c : s) {
ndp = dp;
for (int bal = 0; bal <= n; bal++) {
for (int good = 0; good < 2; good++) {
State cur = dp[bal][good];
if (!cur.cnt) continue;
if (c == '(') {
int ngood = good;
if (bal == 0 && cur.len > 0) ngood = 1;
State &to = ndp[bal + 1][ngood];
to.cnt = (to.cnt + cur.cnt) % MOD;
to.len = (to.len + cur.len + cur.cnt) % MOD;
} else {
if (bal == 0) continue;
State &to = ndp[bal - 1][good];
to.cnt = (to.cnt + cur.cnt) % MOD;
to.len = (to.len + cur.len + cur.cnt) % MOD;
}
}
}
dp.swap(ndp);
}
ll ans = (dp[0][1].len - 2 * dp[0][1].cnt) % MOD;
if (ans < 0) ans += MOD;
cout << ans << '\n';
}
}