学长小清新题表之UOJ 31.猪猪侠再战括号序列

学长小清新题表之UOJ 31.猪猪侠再战括号序列

题目描述

大家好我是来自百度贴吧的_叫我猪猪侠,英文名叫(\_CallMeGGBond)

我不曾上过大学,但这不影响我对离散数学、复杂性分析等领域的兴趣;尤其是括号序列理论,一度令我沉浸其中,无法自拔。至于(OI)算法竞赛,我年轻时确有参加,虽仅获一枚铜牌,但我素性淡泊,毫不在意,毕竟那所谓(FFT)、仙人掌之类,只是些雕虫小技罢了,登不上大雅之堂的;只有括号序列才会真正激发我的研究热情。

我曾天真地以为,凭借我的学识与才能,足可以在这世间安身立命;然而直到沦落街头后,我终才领悟现实的残酷。迫于生计,我只得转向道德与哲学的研究;但我与括号序列之间情愫依旧,难以剪断。

理性的传播总是不顺的,研究的道路也是曲折的,但轻易放弃决不是我的风格;为了继续实现自己的理想,现在我向大家提出一道括号序列的超级大难题。

有一个由 (n)个左括号 “(” 和 n 个右括号 “)” 组成的序列。每次操作时可以选定两个数 (l,r),然后把第 $l $到第 (r) 个括号的顺序翻转(括号的朝向保持不变)。例如将 “()((()(” 翻转第 (3) 到第 (7)个括号后的结果为 “()()(((”。

我希望使用不超过(n)次操作,将这个序列变为一个合法的括号序列。

众所周知,合法括号序列的定义如下:

(()) 是合法括号序列;
如果 (A) 是合法括号序列,则 ((A))是合法括号序列;
如果 $A,B (是合法括号序列,则) AB $是合法括号序列。

自从来到 $UOJ $这个宝地,我的视野变得开阔了,也见识了更多富有人类智慧的人士。我相信各位一定能给我更加满意的答案!

输入格式

一行一个长度为 (2n)的非空字符串表示初始序列。保证字符串只包含左括号和右括号,且左右括号的个数均为 (n)

输出格式

对于给出的字符串,输出调整成合法的括号序列的方案。如果不存在这样的方案输出一行一个整数 (−1)

否则,第一行一个整数 (m)表示要进行 (m)次翻转操作。

接下来 (m)行每行两个整数 (l),(r) 表示要翻转区间 ([l,r])

内的括号顺序。翻转操作会按你输出的顺序执行。

请保证 (m≤n),以及 (1≤l≤r≤2n),否则会被判 (0)分。

如果有多组方案,输出任意一组即可。

样例一

input

)))()(((

output

2
1 6
5 8

explanation

第一次操作后序列变为 “()()))((”。

第二次操作后序列变为 “()()(())”。

限制与约定

测试点编号 n的规模
1 (n≤4)
2、3、4、5 (n≤100)
6、7、8、9、10 (n≤100000)

时间限制:(1s)

空间限制:(256MB)

分析

我们从左到右扫一遍序列,如果是左括号,就把总价值加一,否则就减一

如果当前的总价值变为负数,我们用头指针记录一下当前的位置,同时尾指针一直向后扫

当价值恰好变为(0)时,停止扫描,将头、尾指针所形成的序列反转

代码

#include <bits/stdc++.h>
using namespace std;
const int maxn=1e6+5;
int jlx[maxn],jly[maxn];
char s[maxn];
int main() {
	scanf("%s",s+1);
	int len=strlen(s+1);
	int m=0,cnt=0;
	for(int i=1;i<=len;i++){
		if(s[i]=='(') cnt++;
		else cnt--;
		if(cnt<0){
			jlx[++m]=i;
			while(cnt!=0){
				i++;
				if(s[i]=='(') cnt+=1;
				else cnt+=-1;
			}
			cnt=0;
			jly[m]=i;
		}
	}
	printf("%d
",m);
	for(int i=1;i<=m;i++){
		printf("%d %d
",jlx[i],jly[i]);
	}
	return 0;
}
原文地址:https://www.cnblogs.com/liuchanglc/p/13510350.html