UOJ小清新题表
题目摘要
有一个由 (n) 个左括号 “(
” 和 (n) 个右括号 “)
” 组成的序列。每次操作时可以选定两个数 (l,r),然后把第 (l) 到第 (r) 个括号的顺序翻转(括号的朝向保持不变)。例如将 “()((()(
” 翻转第 (3) 到第 (7) 个括号后的结果为 “()()(((
”。
我希望使用不超过 (n) 次操作,将这个序列变为一个合法的括号序列。
众所周知,合法括号序列的定义如下:
()
是合法括号序列;- 如果
A
是合法括号序列,则(A)
是合法括号序列; - 如果
A,B
是合法括号序列,则AB
是合法括号序列。
数据范围
(nleq 100000)
思路
GGBond!!!
难度:入门
由于新换的主题感觉很好看于是来水博客
显然最好的结构就是((()))
,由于题目保证有解,所以直接双指针 (O(n)) 扫一遍,遇到一个左括号就和左面第一个右括号(如果有)交换即可。可以证明一定是对的。
然后小坑就是字符串最大长度为 (2n),你要是开数组为 (10^5) 的话就 (RE) 了...
代码
#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int tot;
char s[maxn];
int L[maxn],R[maxn];
int main(){
scanf("%s",s+1);
int len=strlen(s+1);
for(int i=1,j=1;i<=len;i++){
if(s[i]=='('){
while(j<i&&s[j]!=')')j++;
if(i!=j){
swap(s[i],s[j]);
L[++tot]=j;R[tot]=i;
}
}
}
printf("%d
",tot);
for(int i=1;i<=tot;i++)
printf("%d %d
",L[i],R[i]);
return 0;
}