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.
Do not try to parse the grammar directly with a normal parenthesis stack. The string has two different “balances”: the usual parenthesis depth, and a hidden balance coming from the deformed grammar.
Let L = '(' and R = ')'. Track a state : is the usual parenthesis depth, and is the hidden bracket depth. Reading R changes to . Reading L changes by , and changes by or depending only on the parity of .
For a fixed starting parity before , the effect of all characters of is linear: changes by a constant , and changes by a constant . Also, the whole scan of only imposes lower bounds on the starting and .
If after reading we are at , the shortest suffix usually has length . The one annoying exception is , where the answer is . That special case is where the problem tries to be a little bastard.
For the prefix , let be the number of Ls read while is even. Then . So the whole problem becomes minimizing under two lower bounds, considering only prefix shapes , , and .
Research note: I used the official Codeforces statement at https://codeforces.com/problemset/problem/2206/M and the official ICPC APAC problem analysis PDF at https://apac26.icpc.tw/assets/championship/2026/problemset-analysis.pdf. The official analysis gives the state-machine direction; the details below fill in the missing algebra.
Write L for ( and R for ). A string has a deformed balance exactly when this scan succeeds:
The transitions are:
and
Why parity? Reading R flips the direction of the hidden brackets, while reading L keeps it. So is the current direction. That is the entire grammar compressed into two integers. Nice, for once.
Now suppose some prefix leaves us at with parity . When we scan the fixed string :
where
The change in depends only on the starting parity . Let that change be :
During the scan of , we also need both coordinates to never go negative. Therefore and only need to satisfy lower bounds:
We compute from the minimum usual prefix balance of .
For , scan once assuming starting parity . Let be the current hidden-depth change, and let , be its minimum and maximum over prefixes. Starting parity just flips all signs, so:
Clamp the bounds at .
Next, we need the shortest suffix from a state to . Count how many future Ls are read in even parity; call that number . A lower-bound calculation gives:
Usually we can make , giving
The only time is impossible is when and is even: we cannot read R, and the next L is forced to be an even-parity L. Then , so
Now handle the prefix. For a prefix , let be the number of Ls read when is even. Check the effect of every transition on
An even-parity L increases it by . An odd-parity L and an R increase it by . Therefore:
So for a non-exceptional suffix, total added length is
If the state after is , add .
All that remains is finding the minimum feasible for each starting parity.
For parity , one R is optimal, so it is enough to consider
This reaches
We need and , so such a exists iff
Also . Thus
For parity , either use no R:
requiring
or use two Rs:
This is feasible iff
So
More Rs cannot improve the minimum : for the same number of even-parity Ls, extra Rs only reduce , making lower bounds harder to satisfy. That is the key false assumption to kill: complicated prefixes look scarier, not better.
For each parity, we test and . Testing cleanly handles the exceptional suffix case, because increasing costs exactly , the same as the exception penalty.
The implementation directly checks whether the feasible interval of contains a non-exceptional state. If the interval has more than one value, it definitely does, since can hold for at most one .
Complexity is per test case, and extra memory besides the input string. With total , this is comfortably fine.
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
const ll INF = (1LL << 60);
while (t--) {
int n;
string s;
cin >> n >> s;
ll bal = 0, minBal = 0;
ll v = 0, minV = 0, maxV = 0;
int parity = 0;
for (char c : s) {
if (c == '(') {
++bal;
v += (parity == 0 ? 1 : -1);
minV = min(minV, v);
maxV = max(maxV, v);
} else {
--bal;
parity ^= 1;
}
minBal = min(minBal, bal);
}
ll a = bal;
ll A = max(0LL, -minBal);
auto exceptional = [&](ll x, ll y, ll b) -> bool {
return x + a == 0 && (y + b) % 2 == 0;
};
auto evalEven = [&](ll f, ll b, ll B) -> ll {
ll C = a + 2 * b - 1;
ll best = INF;
if (f >= A && f >= B) {
ll x = f, y = f;
best = min(best, 4 * f + C + (exceptional(x, y, b) ? 4 : 0));
}
if (f >= 1) {
ll lo = max(0LL, A - f + 2);
ll hi = min(f, f - B);
if (lo <= hi) {
bool allExceptional = false;
if (lo == hi) {
ll g = lo;
ll x = f + g - 2;
ll y = f - g;
allExceptional = exceptional(x, y, b);
}
best = min(best, 4 * f + C + (allExceptional ? 4 : 0));
}
}
return best;
};
auto evalOdd = [&](ll f, ll b, ll B) -> ll {
ll C = a + 2 * b - 1;
ll best = INF;
if (f >= 1) {
ll lo = max(0LL, A - f + 1);
ll hi = min(f, f - B);
if (lo <= hi) {
bool allExceptional = false;
if (lo == hi) {
ll g = lo;
ll x = f + g - 1;
ll y = f - g;
allExceptional = exceptional(x, y, b);
}
best = min(best, 4 * f + C + (allExceptional ? 4 : 0));
}
}
return best;
};
ll ans = INF;
ll b0 = v;
ll B0 = max(0LL, -minV);
ll fAll = max(A, B0);
ll fTwo = max({1LL, B0, (A + B0 + 3) / 2});
ll f0 = min(fAll, fTwo);
ans = min(ans, evalEven(f0, b0, B0));
ans = min(ans, evalEven(f0 + 1, b0, B0));
ll b1 = -v;
ll B1 = max(0LL, maxV);
ll f1 = max({1LL, B1, (A + B1 + 2) / 2});
ans = min(ans, evalOdd(f1, b1, B1));
ans = min(ans, evalOdd(f1 + 1, b1, B1));
cout << ans << '\n';
}
}#include <bits/stdc++.h>
using namespace std;
using ll = long long;
void setIO() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
}
int main() {
setIO();
int t;
cin >> t;
const ll INF = (1LL << 60);
while (t--) {
int n;
string s;
cin >> n >> s;
ll bal = 0, minBal = 0;
ll v = 0, minV = 0, maxV = 0;
int parity = 0;
for (char c : s) {
if (c == '(') {
++bal;
v += (parity == 0 ? 1 : -1);
minV = min(minV, v);
maxV = max(maxV, v);
} else {
--bal;
parity ^= 1;
}
minBal = min(minBal, bal);
}
ll a = bal;
ll A = max(0LL, -minBal);
auto exceptional = [&](ll x, ll y, ll b) -> bool {
return x + a == 0 && (y + b) % 2 == 0;
};
auto evalEven = [&](ll f, ll b, ll B) -> ll {
ll C = a + 2 * b - 1;
ll best = INF;
if (f >= A && f >= B) {
ll x = f, y = f;
best = min(best, 4 * f + C + (exceptional(x, y, b) ? 4 : 0));
}
if (f >= 1) {
ll lo = max(0LL, A - f + 2);
ll hi = min(f, f - B);
if (lo <= hi) {
bool allExceptional = false;
if (lo == hi) {
ll g = lo;
ll x = f + g - 2;
ll y = f - g;
allExceptional = exceptional(x, y, b);
}
best = min(best, 4 * f + C + (allExceptional ? 4 : 0));
}
}
return best;
};
auto evalOdd = [&](ll f, ll b, ll B) -> ll {
ll C = a + 2 * b - 1;
ll best = INF;
if (f >= 1) {
ll lo = max(0LL, A - f + 1);
ll hi = min(f, f - B);
if (lo <= hi) {
bool allExceptional = false;
if (lo == hi) {
ll g = lo;
ll x = f + g - 1;
ll y = f - g;
allExceptional = exceptional(x, y, b);
}
best = min(best, 4 * f + C + (allExceptional ? 4 : 0));
}
}
return best;
};
ll ans = INF;
ll b0 = v;
ll B0 = max(0LL, -minV);
ll fAll = max(A, B0);
ll fTwo = max({1LL, B0, (A + B0 + 3) / 2});
ll f0 = min(fAll, fTwo);
ans = min(ans, evalEven(f0, b0, B0));
ans = min(ans, evalEven(f0 + 1, b0, B0));
ll b1 = -v;
ll B1 = max(0LL, maxV);
ll f1 = max({1LL, B1, (A + B1 + 2) / 2});
ans = min(ans, evalOdd(f1, b1, B1));
ans = min(ans, evalOdd(f1 + 1, b1, B1));
cout << ans << '\n';
}
}