Bracket Sequencing
傳送門
題意:給出n條串,每一條爲空、一個或多個’(‘以及’)'組成,要求組合這n條串(全部都要用到),如果能夠得到要麼爲空,要麼滿足左括號右括號一一對應的串(如"(((())))"、"(()()())"、“空”),則輸出yes,否則輸出no。
思路:
長度放在這裏,數目放在這裏,題號放在這裏,暴力?O(n^2)?想peach。
如果要O(n),據我個人的經驗,要麼可以推出數學公式,要麼可以貪心找到特殊狀態一判斷就能得到答案。
這題都給這麼多括號了,讓我很容易聯想到prefix啊…。
在草稿紙上畫了畫,找到每條字串達到一一對應仍所需要的右括號數,和所需要的左括號數,塞進按照貪心狀態排列的優先隊列,一判斷則得到答案。
這個貪心狀態就是:
首先,大於的字串肯定往左邊放,大於的肯定往右邊放,這樣先分成兩塊。在前一塊裏面,需要越多,越往左放;後一塊裏面,需要越多,越往右放。
當然因爲使用了優先隊列,所以考慮減少一下數目,把和都爲0的字串直接丟掉,因爲這種字串不影響結果。
最後得到的字串隊列,直接從左到右掃過去看看滿不滿足一一對應即可。
那麼如何計算和呢?很簡單,先把字串畫出來,就可以發現,從左到右,如果,遇到’)’,就加,如果,就減;遇到時,直接加即可。(都是靠畫字串模擬的)
貼一下題解給出的計算和的方法:(其實我妹看懂)
是,是。
代碼:
#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");
}