D. A Simple RBS Problem time limit per test2 secon...
Criado em: 29 de março de 2026
Respondido usando GPT-5.4 Thinking por Chat01
Criado em: 29 de março de 2026
Respondido usando GPT-5.4 Thinking por Chat01
D. A Simple RBS Problem
time limit per test2 seconds
memory limit per test256 megabytes
A bracket sequence is called regular if it is possible to obtain a correct arithmetic expression by inserting characters +
and 1
into this sequence. For example, sequences (())(), () and (()(())) are regular, while )(, (() and (()))( are not. Let's call a regular bracket sequence RBS.
You can perform the following operation on any RBS string b
—
Choose any two disjoint, non empty substrings∗
of b
which are RBS and swap the two substrings.
More formally, let m
be the length of b
. You can perform the following operation on b
:
Choose indices 1≤l1<r1<l2<r2≤m
such that the substrings b[l1..r1]
and b[l2..r2]
are both RBS and swap these substrings. The string b
becomes b1…bl1−1bl2bl2+1…br2br1+1…bl2−1bl1bl1+1…br1br2+1…bm
.
You are given two strings s
and t
of length n
(n
is even) such that both s
and t
are RBS.
Determine whether you can transform s
to t
using the above operation any number of times.
∗
A string a
is a substring of a string b
if a
can be obtained from b
by the deletion of several (possibly, zero or all) characters from the beginning and several (possibly, zero or all) characters from the end.
Input
Each test contains multiple test cases. The first line contains the number of test cases t
(1≤t≤104
). The description of the test cases follows.
The first line of each test case contains an integer n
(4≤n≤5⋅105
, n
is even).
The second line of each test case contains a string s
of length n
such that s
is an RBS.
The third line of each test case contains a string t
of length n
such that t
is an RBS.
It is guaranteed that the sum of n
over all test cases does not exceed 5⋅105
.
Output
For each test case, print "YES" if s
can be transformed to t
, and "NO" otherwise.
You can output the answer in any case (upper or lower). For example, the strings "yEs", "yes", "Yes", and "YES" will be recognized as positive responses.
Example
InputCopy
5
4
()()
()()
4
()()
(())
6
(())()
()(())
8
(()()())
()()(())
8
()()(())
()(()())
OutputCopy
YES
NO
YES
NO
YES
Note
In the first test case, the two strings are already same.
In the third test case, we can choose l1=1,r1=4,l2=5,r2=6
and transform s
to t
.
Here is a visualization of the operation performed in this case — give code for this in java and think of all edge cases and see all test cases and give correct solution like a senior coder
(())()→()(())
pythonfrom collections import deque,defaultdict def rbs(s): bal=0 for c in s: bal+=1 if c=='(' else -1 if bal<0:return False return bal==0 def subs(s): n=len(s) res=[] for l1 in range(n): for r1 in range(l1+1,n+1): a=s[l1:r1] if not rbs(a): continue for l2 in range(r1,n): for r2 in range(l2+1,n+1): b=s[l2:r2] if not rbs(b): continue t=s[:l1]+b+s[r1:l2]+a+s[r2:] res.append((l1,r1,l2,r2,t)) return res def classes(n): from itertools import product arr=[''.join(p) for p in product('()', repeat=n) if rbs(''.join(p))] seen=set() cl=[] graph=defaultdict(set) for s in arr: for *_,t in subs(s): graph[s].add(t) graph[t].add(s) for s in arr: if s in seen: continue q=[s]; seen.add(s); comp=[] while q: x=q.pop(); comp.append(x) for y in graph[x]: if y not in seen: seen.add(y); q.append(y) cl.append(sorted(comp)) return arr,cl for n in [2,4,6,8]: arr,cl=classes(n) print("n",n,"count",len(arr),"classes",len(cl),[len(c) for c in cl]) for c in cl: print(c) print()
pythons="()()(())" l1,r1,l2,r2=2,4,5,7 t=s[:l1]+s[l2:r2]+s[r1:l2]+s[l1:r1]+s[r2:] print(t)
pythonfrom collections import deque def path(start,target): q=deque([start]); par={start:None} move={} while q: s=q.popleft() if s==target: break n=len(s) for l1 in range(n): for r1 in range(l1+1,n+1): if not rbs(s[l1:r1]): continue for l2 in range(r1,n): for r2 in range(l2+1,n+1): if not rbs(s[l2:r2]): continue t=s[:l1]+s[l2:r2]+s[r1:l2]+s[l1:r1]+s[r2:] if t not in par: par[t]=s; move[t]=(l1,r1,l2,r2) q.append(t) if target not in
pythondef count_adj(s): return sum(1 for i in range(len(s)-1) if s[i:i+2]=='()') for n in [2,4,6,8,10]: arr=[''.join(p) for p in __import__('itertools').product('()', repeat=n) if rbs(''.join(p))] # compute classes from collections import defaultdict groups=defaultdict(list) for s in arr: groups[count_adj(s)].append(s) # BFS classes from before maybe expensive for 10 maybe skip print(n, {k:len(v) for k,v in groups.items()})
pythonfrom itertools import product def comps(n): arr=[''.join(p) for p in product('()', repeat=n) if rbs(''.join(p))] # build graph maybe manageable for 10? 42 states yes graph=defaultdict(set) for s in arr: for *_,t in subs(s): graph[s].add(t); graph[t].add(s) seen=set(); cls=[] for s in arr: if s in seen: continue q=[s]; seen.add(s); comp=[] while q: x=q.pop(); comp.append(x) for y in graph[x]: if y not in seen: seen.add(y); q.append(y) cls.append(comp) return cls cls10=comps(10) print(len(cls10), sorted(len(c)
pythonfor c in sorted(cls10, key=lambda x:(len(x), min(x))): print("size",len(c),"peaks",count_adj(c[0]), sorted(c)) print()
pythondef leaf_depths(s): st=[]; depths=[] depth=0 for i,c in enumerate(s): if c=='(': depth+=1 st.append(i) else: j=st.pop() if i==j+1: depths.append(depth) depth-=1 return tuple(sorted(depths, reverse=True)) for c in sorted(cls10, key=lambda x:(count_adj(x[0]), len(x), min(x))): rep=min(c) print(rep, "peaks", count_adj(rep), "leafdepths", leaf_depths(rep), "size", len(c))
pythonfor n in [8]: arr,cl=classes(n) for c in sorted(cl, key=lambda x:(len(x),min(x))): rep=min(c) print(rep, len(c), leaf_depths(rep)) print(sorted(c)) print()
pythonfor s in ["()()(())","()(()())","(()())()","(())()()"]: print(s, leaf_depths(s))
pythonfor c in classes(8)[1]: print({leaf_depths(s) for s in c}, c)
pythonclass Node: def __init__(self): self.children=[] def parse_forest(s): stack=[[]] # list of forests, stack top is current children list for c in s: if c=='(': stack.append([]) else: ch=stack.pop() node=Node(); node.children=ch stack[-1].append(node) return stack[0] def leaf_rounds_forest(forest): rounds=[] cur=forest while cur: # count leaves in current forest def count_leaves(nodes): return sum(1 if not nd.children else count_leaves(nd.children) for nd in nodes) rounds.append(count_leaves(cur)) # prune leaves def prune(nodes): new=[] for nd in nodes: if nd.children: nd2=Node(); nd2.children=prune(nd.children) new.append(nd2) return new cur=prune(cur) return rounds for c in classes(8)[1]: rr={tuple(leaf_rounds_forest(parse_forest(s))) for s in c} print(c, rr)
pythondef peak_heights(s): bal=0 res=[] for i,c in enumerate(s): if c=='(': bal+=1 if i+1<len(s) and s[i+1]==')': res.append(bal) else: bal-=1 return tuple(res) for rep in ['(()())(())','((()())())','((()()()))']: print(rep, peak_heights(rep))
pythondef signature(s): forest=parse_forest(s) sig=[] cur=forest while cur: counts=[] def process(nodes): new=[] for nd in nodes: leafc=sum(1 for ch in nd.children if not ch.children) intc=[ch for ch in nd.children if ch.children] if nd.children: counts.append(leafc) nd2=Node(); nd2.children=intc # shallow okay new.append(nd2) return new # include super-root root_leafc=sum(1 for ch in cur if not ch.children) root_int=[ch for ch in cur if ch.children] counts.append(root_leafc) sig.append(tuple(sorted([x for x in counts if x>0], reverse=True))) cur=process(root_int) return tuple(sig) for c in classes(8)[1]: print(sorted(c), {signature(s) for s in c})
pythondef match_arr(s): st=[] m=[None]*len(s) for i,c in enumerate(s): if c=='(': st.append(i) else: j=st.pop(); m[i]=j; m[j]=i return m def inv(s): m=match_arr(s) h=0 n=len(s) while h<n//2 and m[h]==n-1-h: h+=1 p=count_adj(s) return p,h for n in [8,10]: arr,cl=classes(n) ok=True for c in cl: vals={inv(s) for s in c} if len(vals)!=1: ok=False print("class not constant",c,vals) # compare unique invs count with class count print("n",n,"ok",ok,"class count",len(cl),"inv count",len({inv(s) for s in arr})) from collections import defaultdict grp=defaultdict(list) for s in arr: grp[inv(s)].append(s) # check each inv group connected (equal to some class) for key,g in grp.items(): # see if all g in same class cs=[c for c in cl if g[0] in c][0] if set(g)!=set(cs): print("mismatch",key,set(g)-set(cs),set(cs)-set(g)) ok=False break print("final",ok)
pythondef do(s,l1,r1,l2,r2): return s[:l1]+s[l2:r2]+s[r1:l2]+s[l1:r1]+s[r2:] s="()(()())" # prefix first leaf 0..2, inner leaf maybe positions 3..5? let's enumerate RBS substrings and result n=len(s) for l1 in range(n): for r1 in range(l1+1,n+1): if not rbs(s[l1:r1]): continue for l2 in range(r1,n): for r2 in range(l2+1,n+1): if not rbs(s[l2:r2]): continue t=do(s,l1,r1,l2,r2) if t=="()()(())": print((l1,r1,l2,r2), s[l1:r1], s[l2:r2])
The key is that this operation preserves exactly two things:
cnt = the number of occurrences of "()"
This is the number of leaves in the bracket-tree.
outer = how many outermost pairs are forced
In other words, how many times you can peel the whole string as
s = "(" + mid + ")"
and still the first '(' matches the last ')'.
Two RBS strings are transformable iff these two values are equal.
Think of an RBS as an ordered forest:
Then:
"()"A node with no children is exactly a substring "()".
Swapping sibling blocks does not create or destroy leaf nodes, it only moves whole subtrees around.
So the count of "()" is invariant.
If the whole string is primitive, meaning the first '(' matches the last ')', then no valid swapped substring can touch outside that pair unless it is the whole string, which is impossible because the two substrings must be disjoint and non-empty.
So that outermost pair is untouchable.
Apply the same argument recursively inside it.
Hence the number of such forced outer layers is invariant.
A very easy way to compute it:
i satisfy match[i] == n-1-i.After removing those forced outer pairs from both strings, the remaining parts have:
"()").All such forests are equivalent: you can repeatedly expose leaves at the top level and finally reduce everything to the same canonical form:
"()",So equal (cnt, outer) means reachable.
For each string:
cnt = number of i with s[i]=='(' and s[i+1]==')'outer = number of leading matched pairs nesting all the way to the endAnswer is YES iff both values match.
javaimport java.io.*; import java.util.*; public class Main { // Fast input static class FastScanner { private final InputStream in; private final byte[] buffer = new byte[1 << 16]; private int ptr = 0, len = 0; FastScanner(InputStream is) { in = is; } private int read() throws IOException { if (ptr >= len) { len = in.read(buffer); ptr = 0; if (len <= 0) return -1; } return buffer[ptr++]; } String next() throws IOException { StringBuilder sb = new StringBuilder(); int c; do { c = read(); } while (c <= ' ' && c != -1); while (c > ' ') { sb.append((char) c); c = read(); } return sb.toString(); } int nextInt() throws IOException { int c; do { c = read(); } while (c <= ' ' && c != -1); int sign = 1; if (c == '-') { sign = -1; c = read(); } int val = 0; while (c > ' ') { val = val * 10 + (c - '0'); c = read(); } return val * sign; } } static class Info { int peaks; // number of occurrences of "()" int outer; // number of forced outer layers Info(int peaks, int outer) { this.peaks = peaks; this.outer = outer; } } static Info analyze(String s) { int n = s.length(); // 1) count peaks = number of "()" int peaks = 0; for (int i = 0; i + 1 < n; i++) { if (s.charAt(i) == '(' && s.charAt(i + 1) == ')') { peaks++; } } // 2) build matching brackets int[] match = new int[n]; int[] stack = new int[n]; int top = 0; for (int i = 0; i < n; i++) { char c = s.charAt(i); if (c == '(') { stack[top++] = i; } else { int j = stack[--top]; match[i] = j; match[j] = i; } } // 3) count forced outer layers int outer = 0; while (outer < n / 2 && match[outer] == n - 1 - outer) { outer++; } return new Info(peaks, outer); } public static void main(String[] args) throws Exception { FastScanner fs = new FastScanner(System.in); StringBuilder out = new StringBuilder(); int T = fs.nextInt(); while (T-- > 0) { int n = fs.nextInt(); String s = fs.next(); String t = fs.next(); Info a = analyze(s); Info b = analyze(t); if (a.peaks == b.peaks && a.outer == b.outer) { out.append("YES\n"); } else { out.append("NO\n"); } } System.out.print(out); } }
(((())))()()()()"()" but different forced outer depth5e5For each test case:
O(n) timeO(n) memoryTotal over all test cases: O(sum n).
If you want, I can also give a shorter competitive version without comments.