[ACM]【greedy】Atcoder 167 Bracket Sequencing

Bracket Sequencing

传送门
题意:给出n条串,每一条为空、一个或多个’(‘以及’)'组成,要求组合这n条串(全部都要用到),如果能够得到要么为空,要么满足左括号右括号一一对应的串(如"(((())))"、"(()()())"、“空”),则输出yes,否则输出no。
题目图片

思路:

长度放在这里,数目放在这里,题号放在这里,暴力?O(n^2)?想peach。
如果要O(n),据我个人的经验,要么可以推出数学公式,要么可以贪心找到特殊状态一判断就能得到答案。
这题都给这么多括号了,让我很容易联想到prefix啊…。

在草稿纸上画了画,找到每条字串达到一一对应仍所需要的右括号数 r r r,和所需要的左括号数 l l l,塞进按照贪心状态排列的优先队列,一判断则得到答案。

这个贪心状态就是:
首先, r r r大于 l l l的字串肯定往左边放, l l l大于 r r r的肯定往右边放,这样先分成两块。在前一块里面,需要 r r r越多,越往左放;后一块里面,需要 l l l越多,越往右放。

当然因为使用了优先队列,所以考虑减少一下数目,把 r r r l l l都为0的字串直接丢掉,因为这种字串不影响结果。

最后得到的字串队列,直接从左到右扫过去看看满不满足一一对应即可。

那么如何计算 r r r l l l呢?很简单,先把字串画出来,就可以发现,从左到右,如果 r = 0 r=0 r=0,遇到’)’,就加 l l l,如果 r ! = 0 r!=0 r!=0,就减 r r r;遇到 ( ( (时,直接加 r r r即可。(都是靠画字串模拟的)

贴一下题解给出的计算 r r r l l l的方法:(其实我妹看懂)
l l l A i A_i Ai r r r B i B_i Bi
在这里插入图片描述

代码:

#include<bits/stdc++.h>
using namespace std;
char str[1000005];
struct node{
	int l,r;
	bool operator <(node b)const{
		//原来是从大轮到小。 
		//return 0:前者置前,b置后 
		//return 1:后者置前,b置前 
		if(r-l>=0) {
			if(b.r-b.l<=0) return 0;
			else return b.l<l;
		}
		else if(r-l<=0) {
			if(b.r-b.l>=0) return 1;
			else return b.r>r;
		} 
	}
};
int main(){
	int n;
	scanf("%d",&n);
	getchar();
	priority_queue<node>pq;
	for(int i=1;i<=n;i++) {
		//用fgets才能扫进空字串
		fgets(str,1000005,stdin);
		str[strlen(str)-1]='\0';
		int l=0,r=0;
		for(int j=0;j<strlen(str);j++){
			if(str[j]=='(') r++;
			else{
				if(r!=0) r--;
				else l++;
			}
		}
		if(l==0&&r==0) continue;
		pq.push(node{l,r});
	}
	int l=0,r=0;
	//特判全空,不然下面取出会RE
	if(pq.empty()){
		printf("Yes\n");
		return 0;
	}
	node cur=pq.top();
	pq.pop();
	l=cur.l,r=cur.r;
	while(!pq.empty()){
		cur=pq.top();
		pq.pop();
		int tl=cur.l,tr=cur.r;
		//其实就是从左至右更新r和l
		if(r>tl) {
			r-=tl;
			r+=tr;
		}
		else {
			l+=(tl-r);
			r=tr;
		}
		if(l!=0) break;
	}
	if(r==0&&l==0) printf("Yes\n");
	else printf("No\n");
} 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值