1. 程式人生 > 實用技巧 >【UR #2】豬豬俠再戰括號序列

【UR #2】豬豬俠再戰括號序列

UOJ小清新題表

題目摘要

UOJ連結

有一個由 \(n\) 個左括號 “(” 和 \(n\) 個右括號 “)” 組成的序列。每次操作時可以選定兩個數 \(l,r\),然後把第 \(l\) 到第 \(r\) 個括號的順序翻轉(括號的朝向保持不變)。例如將 “()((()(” 翻轉第 \(3\) 到第 \(7\) 個括號後的結果為 “()()(((”。

我希望使用不超過 \(n\) 次操作,將這個序列變為一個合法的括號序列。

眾所周知,合法括號序列的定義如下:

  • () 是合法括號序列;
  • 如果 A 是合法括號序列,則 (A) 是合法括號序列;
  • 如果 A,B 是合法括號序列,則 AB 是合法括號序列。

資料範圍

\(n\leq 100000\)

思路

難度:入門

由於新換的主題感覺很好看於是來水部落格

顯然最好的結構就是((())),由於題目保證有解,所以直接雙指標 \(O(n)\) 掃一遍,遇到一個左括號就和左面第一個右括號(如果有)交換即可。可以證明一定是對的。

然後小坑就是字串最大長度為\(2n\),你要是開陣列為\(10^5\)的話就\(RE\)了...

程式碼

#include <bits/stdc++.h>
using namespace std;
const int maxn=2e5+10;
int tot;
char s[maxn];
int L[maxn],R[maxn];

int main(){
    scanf("%s",s+1);
    int len=strlen(s+1);
    for(int i=1,j=1;i<=len;i++){
        if(s[i]=='('){
            while(j<i&&s[j]!=')')j++;
            if(i!=j){
                swap(s[i],s[j]);
                L[++tot]=j;R[tot]=i;
            }
        }
    }
    printf("%d\n",tot);
    for(int i=1;i<=tot;i++)
        printf("%d %d\n",L[i],R[i]);
    return 0;
}