题解 | # Bracket Coloring #

Bracket Coloring

https://ac.nowcoder.com/acm/contest/127703/F

没做过类似的题目,将括号想象成节点,然后转化为二分图的形式

就是将每一对括号想象成一个节点:
根据条件一:一对括号的染色情况必须相同,每一对匹配的括号,是一个颜色绑定的整体。可以直接把一对括号抽象成一个节点,节点的颜色就是这对括号的颜色,不用再单独考虑每个括号
根据条件二:相邻位置的括号字符相同,其颜色必须不同,假设相邻的两个相同字符,分别属于节点 u 和节点 v。因为这两个括号的颜色必须不同,而它们的颜色就是所属节点的颜色,所以节点 u 和节点 v 的颜色必须不同

那么问题转化为一个无向图二染色问题:
现在这里有若干个节点(对应每一对匹配的括号)
两个节点之间连一条边,当且仅当:存在相邻的两个相同字符,分别属于这两个节点
给每个节点染红 / 蓝,要求有边相连的节点颜色必须不同
求有多少种合法的染色方案?
答案就是
结论一:这个图一定是二分图,绝对有合法染色方案,不会出现答案为 0 的情况
合法括号序列的嵌套以及并列结构,决定了我们构建的图是无环的(森林),而无环图一定是二分图,不会出现奇环导致的染色矛盾,所以一定能染成功
结论二:每个连通分量只有 2 种染色方案
对于二分图的二染色,一旦你选定了连通分量里任意一个节点的颜色(红 / 蓝),整个连通分量里所有节点的颜色就被唯一确定了(相邻节点必须不同)

这段代码是给每对括号进行标号,用vector模拟栈
vector<int> pid(n + 10), sta;
int idx = 0;
for(int i = 1; i <= n; i ++){
    if(s[i] == '(') sta.push_back(i);
    else{
        int last = sta.back();
        pid[last] = pid[i] = ++ idx;
        sta.pop_back();
    }
}

总代码:
#include<bits/stdc++.h>
using namespace std;

#define endl '\n'
#define int long long
#define IOS ios::sync_with_stdio(false);cin.tie(NULL);cout.tie(NULL);
#define HelloWorld IOS;


const int N = 200010;
const int mod = 998244353;

int p[N];

int find(int x){
    if(x != p[x]) p[x] = find(p[x]);
    return p[x]; 
}

int ksm(int a, int b, int p){
    int sum = 1;
    while(b){
        if(b & 1) sum = (sum * a) % p;
        b >>= 1;
        a = (a * a) % p;
    }
    return sum;
}

void solve(){
    int n; cin >> n;
    vector<char> s(n + 10);
    for(int i = 1; i <= n; i ++) cin >> s[i];
    vector<int> pid(n + 10), sta;
    int idx = 0;
    for(int i = 1; i <= n; i ++){
        if(s[i] == '(') sta.push_back(i);
        else{
            int last = sta.back();
            pid[last] = pid[i] = ++ idx;
            sta.pop_back();
        }
    }

    for(int i = 1; i <= idx; i ++) p[i] = i;
    for(int i = 1; i <= n - 1; i ++){
        if(s[i] == s[i + 1]){
            int u = pid[i], v = pid[i + 1];
            int fu = find(u), fv = find(v);
            if(fu != fv) p[fu] = fv;
        }
    }

    int cnt = 0;
    for(int i = 1; i <= idx; i ++) cnt += (p[i] == i);
    cout << ksm(2, cnt, mod) << endl;
    return ;
}
signed main(){
    HelloWorld;
    
    int tt; cin >> tt;
    while(tt --) solve();
    return 0;
}
全部评论

相关推荐

评论
点赞
收藏
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务