uoj problem 31 猪猪侠再战括号序列

题目大意:

给定一个长度为2n的括号序列.定义一个关于区间[l,r]的翻转操作为位置平移对调.
即翻转")))()("可以得到"()()))(("
用不超过n次翻转操作使给出的序列变为合法的序列.(n leq 100000)

题解:

因为给出了n次翻转操作的机会。
如果我们考虑构造出"(((((())))))"的合法的括号序列
很容易得到这样的策略:

  • 从左到右依次检查左半部分,如果出现了右括号,就向右找到第一个出现的左括号然后交换两括号,使当前位置变为左括号。

这样的话算上翻转序列的复杂度一共是(O(n^3))
但是仔细思考可以发现,我们每次的翻转序列操作只交换了左右两端的括号。
因为右端点是从左端点开始向右寻找找到的第一个左括号。所以中间的括号全部都是右括号。
区间翻转不会对其造成任何影响
交换两端点即可,复杂度降到(O(n^2))
我们又发觉右端点是单调的.
复杂度降到(O(n))

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;
inline void read(int &x){
	x=0;char ch;bool flag = false;
	while(ch=getchar(),ch<'!');if(ch == '-') ch=getchar(),flag = true;
	while(x=10*x+ch-'0',ch=getchar(),ch>'!');if(flag) x=-x;
}
#define rg register int
#define rep(i,a,b) for(rg i=(a);i<=(b);++i)
#define per(i,a,b) for(rg i=(a);i>=(b);--i)
const int maxn = 200010;
char s[maxn];
struct Node{
	int l,r;
	Node(){}
	Node(const int &a,const int &b){
		l = a;r = b;
	}
}sta[maxn];
int top;
int main(){
	scanf("%s",s+1);
	int n = strlen(s+1),j = 0;
	rep(i,1,n){
		if(s[i] == ')'){
			j = max(i+1,j);
			for(;j<=n;++j) if(s[j] == '('){
				sta[++top] = Node(i,j);
				swap(s[i],s[j]);
				break;
			}
		}
	}
	printf("%d
",top);
	rep(i,1,top){
		printf("%d %d
",sta[i].l,sta[i].r);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/Skyminer/p/6866890.html