括号题

找个时间回顾一下。

P7914 括号序列

https://www.luogu.com.cn/problem/P7914

P8003 Hard Brackets Inserting

https://www.luogu.com.cn/problem/solution/P8003

CF1709C

题意:给定一个匹配括号序列,将部分位置变成问号,问是否有唯一的方案将所有问号变成左括号或右括号,使得该括号序列依然为匹配的。

分析:
首先我们考虑构造一组方案。先算出括号中左括号和右括号的位置。当左括号没用完的时候我们优先使用左括号。否则使用右括号。

为什么这么做呢?证明:因为题目保证一定存在一组合法的括号序列,故一定有一种合法的序列。假设这种方案(记为 \(S\))不成立,那么一定存在另一种方案(记为 \(T\))成立。并且这种方案一定是 \(S\) 中经历若干次左右括号交换而来的。考虑在 \(S\) 的某个位置 \(x\) 出现不成立的情况,说明 \(1 \sim x\) 中右括号数量大于左括号数量。考虑被交换的位置 \(y,z\),满足 \(S_y=\mathtt{'('},S_z=\mathtt{')'}\),则 \(y<z\) 一定成立。

  1. 如果 \(x<y<z\),那么交换之后,\(x\) 左边右括号和左括号数量不变,依然会在 \(x\) 处不成立。
  2. 如果 \(y<x<z\),那么交换之后,\(x\) 左边会多出一个右括号少掉一个左括号,更不会成立。
  3. 如果 \(y<z<x\),那么交换之后,\(x\) 左边右括号和左括号数量不变,依然会在 \(x\) 处不成立。
    与假设矛盾,原命题成立。

然后我们考虑是否能构造出其他方案合法。考虑这个方案:将 \(S\) 中最后一个左括号和第一个右括号交换,依然类似的思路证明该方案次优。判断这种方案是否可行,如果可行那么 \(\mathtt{NO}\),否则 \(\mathtt{YES}\)。(如果不存在这种方案,也就是问号中没填左/右括号,一定 \(\mathtt{YES}\))。

#include<bits/stdc++.h>
using namespace std;
#define f(i, a, b) for(int i = (a); i <= (b); i++)
#define cl(i, n) i.clear(),i.resize(n);
#define endl '\n'
typedef long long ll;
typedef unsigned long long ull;
typedef pair<int, int> pii;
const int inf = 1e9;
int l, r, q, nl, nr;
stack<int> lft; queue<int> rgt;
bool check(string s){
    int cnt=0;
    f(i,0,(int)s.size()-1){if(s[i]=='(')cnt++;else cnt--;if(cnt<0)return 0;}
    return 1;
}
int main() {
    ios::sync_with_stdio(0);
    cin.tie(NULL);
    cout.tie(NULL);
    int t; cin >> t;
    while(t--) {
        while(!lft.empty())lft.pop();while(!rgt.empty())rgt.pop();
        string s; cin >> s; int n = s.size();l=r=0;
        f(i, 0, (int)s.size() - 1) {
            if(s[i]=='(')l++; else if(s[i]==')')r++; 
        }
        nl=(n/2)-l, nr=(n/2)-r;
        f(i, 0, (int)s.size() - 1) {
            if(s[i]=='?'){
                if(nl) {lft.push(i);s[i]='(';nl--;}
                else {rgt.push(i);s[i]=')';nr--;}
            }
        }
        if(lft.empty()||rgt.empty()) {cout<<"YES\n";continue;}
        int x=lft.top(), y=rgt.front(); 
        swap(s[x],s[y]); if(check(s)){cout<<"NO\n";} else {cout<<"YES\n";}
    }
    return 0;
}
posted @ 2022-07-12 16:34  OIer某罗  阅读(50)  评论(0编辑  收藏  举报