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.
Track prefix balances, not strings. The final number of ( and ) never changes, so the only way to fail after rotation is some prefix becoming negative.
Let the chosen positions be , and write bracket values as for ( and for ). For a prefix ending after , the balance change telescopes to , where is the value of the rightmost chosen bracket.
If the rightmost chosen bracket is (, then is never negative. So every subsequence whose rightmost chosen position is an opening bracket is automatically valid. Count those by with -based indices.
If the rightmost chosen bracket is ), the only dangerous moments are after a chosen ( and before the next chosen position. During those gaps the new balance is the old balance minus , so the old balance must stay at least .
Scan left to right for the rightmost-) case. Keep two counts: partial chosen subsequences whose latest chosen bracket is ( or ). Kill the latest-( count whenever the current prefix balance before this position is , then add the current character with the tiny transitions.
Research note: I checked the official Codeforces editorial page, which currently has the 2201C section but no loaded tutorial body, plus CF Step's model-code recurrence and hints, and an independent kmjp DP writeup: official page, CF Step hints, CF Step code, kmjp writeup. The proof below is from the statement; sources were only used to sanity-check the intended linear DP.
Let the original prefix balance be
The original string is regular, so every and the final balance is .
Choose positions
and let if , otherwise . After the cyclic right shift, position receives the old value from , with receiving from .
Now look at the balance difference after a prefix that contains exactly the first chosen positions. It is
This telescopes:
That is the whole problem. No need to simulate the subset circus.
There are only three possible differences: . A negative difference happens only when:
), so ;(, so .So split by the rightmost chosen position.
Case 1: the rightmost chosen bracket is (
Then , so is either or . Prefix balances never decrease. Therefore every such non-empty subsequence is valid.
If this rightmost opening bracket is at -based index , every earlier position can be chosen or skipped independently, and position must be chosen. That gives subsequences.
So this part contributes
This also counts singleton ( subsequences, correctly, because shifting one selected character is a no-op.
Case 2: the rightmost chosen bracket is )
Now dangerous intervals exist. Suppose some chosen ( is followed by the next chosen position later. From that ( until just before the next chosen position, the latest chosen bracket is ( while the final selected bracket is ), so the shifted balance is
For validity we need
throughout that whole gap.
This gives a clean left-to-right DP.
Let be the balance before reading . Maintain:
(, and whose open dangerous gap has stayed at balance at least so far;). There is no dangerous open gap in this state.Before processing position , if , every partial subsequence ending in ( is dead: if we kept skipping until here, the interval after that chosen ( reached balance or , and later subtracting would break regularity. So:
Now process .
If , taking it can extend any alive partial subsequence, or start a new one. The latest chosen bracket becomes (:
Skipping it is already represented by keeping the old .
If , taking it can also extend any alive partial subsequence, or start a singleton ). Since this ) may be the rightmost selected bracket, all these choices are complete valid answers right now:
They can also be partial subsequences for a later rightmost ), now ending in ):
The singleton ) is valid because a length- shift changes nothing.
Correctness proof
For any chosen subsequence, the prefix-balance change after the first chosen positions is exactly by telescoping. Therefore if the rightmost chosen bracket is (, no prefix balance decreases, so all such subsequences are valid and the closed form counts them exactly by their rightmost position.
If the rightmost chosen bracket is ), the only possible negative change is , and it happens exactly while the most recent chosen bracket is (. Thus the necessary and sufficient condition is: every gap after a chosen ( and before the next chosen position must have original balance at least .
The DP stores exactly the partial subsequences satisfying all already-closed gaps, plus possibly one currently open gap when the latest chosen bracket is (. The reset when removes exactly the partial subsequences whose open gap has just become impossible. The transitions append the current position or skip it, preserving the latest chosen bracket state. When a ) is taken, every alive partial subsequence plus the singleton case forms a valid full subsequence with rightmost bracket ), so adding counts each such subsequence exactly once, at its rightmost position.
The two cases are disjoint because the rightmost chosen bracket is either ( or ). Together they cover every non-empty subsequence.
Edge cases
( is counted in the closed form, singleton ) in the DP.Complexity
Each character is processed once, with state.
per test case, total time, and extra memory.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const ll MOD = 998244353;
int t;
cin >> t;
while (t--) {
int n;
string s;
cin >> n >> s;
ll ans = 0;
ll pow2 = 1;
for (char c : s) {
if (c == '(') {
ans += pow2;
if (ans >= MOD) ans -= MOD;
}
pow2 = pow2 * 2 % MOD;
}
ll dpOpen = 0, dpClose = 0;
int bal = 0;
for (char c : s) {
if (bal <= 1) dpOpen = 0;
ll add = (1 + dpOpen + dpClose) % MOD;
if (c == ')') {
ans += add;
ans %= MOD;
dpClose += add;
dpClose %= MOD;
} else {
dpOpen += add;
dpOpen %= MOD;
}
bal += (c == '(' ? 1 : -1);
}
cout << ans % MOD << '\n';
}
return 0;
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
const ll MOD = 998244353;
int t;
cin >> t;
while (t--) {
int n;
string s;
cin >> n >> s;
ll ans = 0;
ll pow2 = 1;
for (char c : s) {
if (c == '(') {
ans += pow2;
if (ans >= MOD) ans -= MOD;
}
pow2 = pow2 * 2 % MOD;
}
ll dpOpen = 0, dpClose = 0;
int bal = 0;
for (char c : s) {
if (bal <= 1) dpOpen = 0;
ll add = (1 + dpOpen + dpClose) % MOD;
if (c == ')') {
ans += add;
ans %= MOD;
dpClose += add;
dpClose %= MOD;
} else {
dpOpen += add;
dpOpen %= MOD;
}
bal += (c == '(' ? 1 : -1);
}
cout << ans % MOD << '\n';
}
return 0;
}