[ACM]【greedy】Atcoder 167 Bracket Sequencing

Bracket Sequencing

傳送門
題意:給出n條串,每一條爲空、一個或多個’(‘以及’)'組成,要求組合這n條串(全部都要用到),如果能夠得到要麼爲空,要麼滿足左括號右括號一一對應的串(如"(((())))"、"(()()())"、“空”),則輸出yes,否則輸出no。
題目圖片

思路:

長度放在這裏,數目放在這裏,題號放在這裏,暴力?O(n^2)?想peach。
如果要O(n),據我個人的經驗,要麼可以推出數學公式,要麼可以貪心找到特殊狀態一判斷就能得到答案。
這題都給這麼多括號了,讓我很容易聯想到prefix啊…。

在草稿紙上畫了畫,找到每條字串達到一一對應仍所需要的右括號數rr,和所需要的左括號數ll,塞進按照貪心狀態排列的優先隊列,一判斷則得到答案。

這個貪心狀態就是:
首先,rr大於ll的字串肯定往左邊放,ll大於rr的肯定往右邊放,這樣先分成兩塊。在前一塊裏面,需要rr越多,越往左放;後一塊裏面,需要ll越多,越往右放。

當然因爲使用了優先隊列,所以考慮減少一下數目,把rrll都爲0的字串直接丟掉,因爲這種字串不影響結果。

最後得到的字串隊列,直接從左到右掃過去看看滿不滿足一一對應即可。

那麼如何計算rrll呢?很簡單,先把字串畫出來,就可以發現,從左到右,如果r=0r=0,遇到’)’,就加ll,如果r!=0r!=0,就減rr;遇到((時,直接加rr即可。(都是靠畫字串模擬的)

貼一下題解給出的計算rrll的方法:(其實我妹看懂)
llAiA_irrBiB_i
在這裏插入圖片描述

代碼:

#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");
} 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章