• [NOI 2017]游戏


    Description

    题库链接

    小 L 计划进行 (n) 场游戏,每场游戏使用一张地图,小 L 会选择一辆车在该地图上完成游戏。

    小 L 的赛车有三辆,分别用大写字母 A、B、C 表示。地图一共有四种,分别用小写字母 x、a、b、c 表示。其中,赛车 A 不适合在地图 a 上使用,赛车 B 不适合在地图 b 上使用,赛车 C 不适合在地图 c 上使用,而地图 x 则适合所有赛车参加。适合所有赛车参加的地图并不多见,最多只会有 d 张。

    (n) 场游戏的地图可以用一个小写字母组成的字符串描述。例如: S=xaabxcbc 表示小 L 计划进行 (8) 场游戏,其中第 (1) 场和第 (5) 场的地图类型是 x ,适合所有赛车,第 (2) 场和第 (3) 场的地图是 a ,不适合赛车 A ,第 (4) 场和第 (7) 场的地图是 b ,不适合赛车 B ,第 (6) 场和第 (8) 场的地图是 c ,不适合赛车 C 。

    小 L 对游戏有一些特殊的要求,这些要求可以用四元组 ((i, h_i, j, h_j)) 来描述,表示若在第 (i) 场使用型号为 (h_i) 的车子,则第 (j) 场游戏要使用型号为 (h_j) 的车子。

    你能帮小 L 选择每场游戏使用的赛车吗?如果有多种方案,输出任意一种方案。如果无解,输出 -1(不含双引号)。

    (1leq nleq 50000,dleq 8,1leq mleq 100000)

    Solution

    容易发现,对于除 x 以外的位置,只能选择两个中的一个,可以建立 ( ext{2-SAT}) 模型。剩下的 x 的位置,因为数量少,可以枚举。不过只要枚举这一位置是 a 或是 b ,因为 c 的情况已经被前两种情况涵盖了。

    对于边的建立,对于四元组 ((i, h_i, j, h_j)) ,记第 (i) 个位置上的字符为 (S_i)

    • (h_i=S_i) ,直接忽略;
    • (h_j=S_j) ,建一条 (i ightarrow i') 的边,表示强制选择 (S_i) 对应的另一种字符;
    • 其余情况,建边 (i ightarrow j)(j' ightarrow i')

    直接跑 ( ext{2-SAT}) 即可,复杂度是 (Oleft(2^d imes(m+n) ight))

    Code

    #include <bits/stdc++.h>
    #define pb push_back
    using namespace std;
    const int N = (50000+5)<<1, M = 100000+5;
    
    int n, d, m, lst[10], tot, a[M], b[M], h1[M], h2[M];
    char ch[N], s[2];
    struct tt {int to, next; } edge[M<<1];
    int path[N], top;
    vector<int> scc[N], to[N];
    vector<int>::iterator it;
    queue<int> Q;
    int dfn[N], low[N], ins[N], id[N], in[N], num, times, S[N], tp, cs[N];
    
    void add(int u, int v) {edge[++top] = (tt){v, path[u]}, path[u] = top; }
    int idx(int i, int c) {
        if (ch[i] != 'c') return i+n*(c == 'C');
        return i+n*(c == 'B');
    }
    int inv(int x) {return x <= n ? x+n : x-n; }
    void tarjan(int u) {
        dfn[u] = low[u] = ++times; ins[u] = 1; S[++tp] = u;
        for (int i = path[u], v; i; i = edge[i].next) {
            v = edge[i].to;
            if (!dfn[v]) tarjan(v), low[u] = min(low[u], low[v]);
            else if (ins[v]) low[u] = min(low[u], dfn[v]);
        }
        if (dfn[u] == low[u]) {
            ++num; int v = 0;
            do {
                v = S[tp--]; id[v] = num;
                scc[num].pb(v); ins[v] = 0;
            }while (v != u);
        }
    }
    void solve() {
        memset(path, top = 0, sizeof(path));
        for (int i = 1; i <= m; i++) {
            if (ch[a[i]] == h1[i]+32) continue;
            else if (ch[b[i]] == h2[i]+32) add(idx(a[i], h1[i]), inv(idx(a[i], h1[i])));
            else {
                int x = idx(a[i], h1[i]), y = idx(b[i], h2[i]);
                add(x, y), add(inv(y), inv(x));
            }
        }
        for (int i = 1; i <= n*2; i++) scc[i].clear(); num = 0;
        memset(dfn, times = 0, sizeof(dfn));
        for (int i = 1; i <= n*2; i++) if (!dfn[i]) tarjan(i);
        for (int i = 1; i <= n; i++) if (id[i] == id[i+n]) return;
        for (int u = 1; u <= n*2; u++)
            for (int i = path[u], v; i; i = edge[i].next)
                if (id[u] != id[v = edge[i].to]) to[id[v]].pb(id[u]), ++in[id[u]];
        for (int i = 1; i <= num; i++) if (in[i] == 0) Q.push(i);
        while (!Q.empty()) {
            int u = Q.front(); Q.pop();
            if (ins[u]) continue; cs[u] = 1;
            for (it = scc[u].begin(); it != scc[u].end(); it++) ins[id[inv(*it)]] = 1;
            for (it = to[u].begin(); it != to[u].end(); it++) if (!(--in[*it])) Q.push(*it);
        }
        for (int i = 1; i <= n; i++)
            if (cs[id[i]]) putchar('A'+(ch[i] == 'a'));
            else putchar('C'-(ch[i] == 'c'));
        exit(0);
    }
    void dfs(int x) {
        if (x > tot) {solve(); return; }
        ch[lst[x]] = 'a'; dfs(x+1);
        ch[lst[x]] = 'b'; dfs(x+1);
    }
    void work() {
        scanf("%d%d%s", &n, &d, ch+1);
        for (int i = 1; i <= n; i++) if (ch[i] == 'x') lst[++tot] = i;
        scanf("%d", &m);
        for (int i = 1; i <= m; i++) {
            scanf("%d%s", &a[i], s); h1[i] = s[0];      
            scanf("%d%s", &b[i], s); h2[i] = s[0];
        }
        dfs(1); puts("-1");
    }
    int main() {work(); return 0; }
  • 相关阅读:
    14GDB代码反向执行
    AcWing 1144. 连接格点
    AcWing 1143. 联络员
    AcWing 1141 局域网
    AcWing 1148 秘密的牛奶运输
    AcWing 904 虫洞
    AcWing 1146. 新的开始  
    AcWing 1140. 最短网络
    AcWing 346 走廊泼水节
    AcWing 1145. 北极通讯网络
  • 原文地址:https://www.cnblogs.com/NaVi-Awson/p/9288356.html
Copyright © 2020-2023  润新知