E. Bring Balance time limit per test1 second memory limit per test256 megabytes inputstandard input outputstandard output Alina has a bracket sequence s of length 2n, consisting of n opening brackets '(' and n closing brackets ')'. As she likes balance, she wants to turn this bracket sequence into a balanced bracket sequence. In one operation, she can reverse any substring of s. What's the smallest number of operations that she needs to turn s into a balanced bracket sequence? It can be shown that it's always possible in at most n operations. As a reminder, a sequence of brackets is called balanced if one can turn it into a valid math expression by adding characters + and 1. For example, sequences (())(), (), and (()(())) are balanced, while )(, ((), and (()))( are not. Input The first line of the input contains a single integer t (1≤t≤2⋅104) — the number of test cases. The description of the test cases follows. The first line of each test case contains a single integer n (1≤n≤105). The second line of each test case contains a string s of length 2n, consisting of n opening and n closing brackets. The sum of n over all test cases doesn't exceed 2⋅105. Output For each test case, in the first line output a single integer k (0≤k≤n) — the smallest number of operations required. The i-th of the next k lines should contain two integers li,ri (1≤li≤ri≤2n), indicating that in the i-th operation, Alina will reverse the substring slsl+1…sr−1sr. Here the numeration starts from 1. If there are multiple sequences of operations with the smallest length which transform the sequence into a balanced one, you can output any of them. Example inputCopy 3 2 (()) 5 ())((()))( 6 ())((()))(() outputCopy 0 2 3 4 9 10 1 2 11 Note In the first test case, the string is already balanced. In the second test case, the string will be transformed as follows: ())((()))( → ()()(()))( → ()()(())(), where the last string is balanced. In the third test case, the string will be transformed to ((()))((())), which is balanced.
思路:
- 核心: 把 ‘(’ 弄成 1, ‘)’弄成 -1;,在利用前缀和, 画出前缀和的图像,
- 前缀和为0的点就是刚刚匹配好, 出现<0的点 就代表这个数列不合规了
- reverse 这个 某一段 就是把趋势对调,- + - + 变成 + - + -, L-1的值和 R的,值还是不变 (注意不是R+1)(前缀和嘛)
- 于是对于起点-1和终点值一样的reverse 就是相当于前缀和图像向上面对翻
- 本题:
- 结论 1 , 最多2 次就可以把 这个数列搞合格 (本题 n个1和n个-1) ,n>>=1;
- reverse 1- x, x+1,n (x,前缀和最大的那个点)
- 贪心简要推: 1-X 先把 上升趋势给他搞上去,之后不管怎么变 都不会小于0,(Codeforce 有严格推论)
- X+1 - n, 把下降的尽量往后边放.
- 所以 只需要在判读 0,1步骤有没有
- 0,就直接判断就行了 arr[i]>=0;
- 1, 首先找到 L ,R 把所有的小于0的点包裹进去
- 然后让 L 变成 max(arr[1]-arr[L])的点 贪心思想: 让前面的值(起点)尽量大,为后面提供容错,下降趋势往后面衍生,
- R 也是选一个后面的最大值, 贪心思想: 让一个尽量大的上升趋势往前面排.
- 注意具体操作时的 节点问题 , L 和R 有点区别的. L要+1,(i=0开始,防止 l=1,还要+1,(L要=1)) (一开始就下降的时候)
#include <bits/stdc++.h> using namespace std; #define M 400005 #define ri register int template <class G> void read(G &x) { x=0;int f=0;char ch=getchar(); while(ch<'0'||ch>'9'){f|=ch=='-';ch=getchar();} while(ch>='0'&&ch<='9'){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} x=f?-x:x; return ; } int t; int n; long long arr[M]; int main(){ ios::sync_with_stdio(false); cin.tie(0); cin>>t; while(t--) { cin>>n; n*=2; string s; cin>>s; vector<int>p(n+1); int mx=1; for(ri i=0;i<s.length();i++) { if(s[i]=='(') p[i+1]=1; else p[i+1]=-1; arr[i+1]=arr[i]+p[i+1]; if(arr[mx]<arr[i+1]) mx=i+1; } int flag=1; for(ri i=1;i<=n;i++) { if(arr[i]<0) { flag=0;break; } } if(flag) { printf("0\n"); continue; } int l=0,r=0; for(ri i=1;i<=n;i++) { if(arr[i]<0) { l=i; break; } } for(ri i=n;i>=1;i--) { if(arr[i]<0) { r=i; break; } } r++; int tmp=l; for(ri i=0;i<=tmp;i++) { if(arr[i]>arr[l]) l=i; } tmp=r; for(ri i=tmp+1;i<=n;i++) { if(arr[i]>arr[r]) r=i; } l++; reverse(s.begin()+l-1,s.begin()+r+1-1); flag=1; for(ri i=0;i<s.length();i++) { if(s[i]=='(') p[i+1]=1; else p[i+1]=-1; arr[i+1]=arr[i]+p[i+1]; if(arr[i+1]<0) { flag=0;break; } } if(flag) { printf("1\n"); printf("%d %d\n",l,r); continue; } printf("2\n"); printf("1 %d %d %d\n",mx,mx+1,n); } return 0; }
最后小声BB,他题目还要要求L,R尽量小嘛?????????