「解题报告」P9169 [省选联考 2023] 过河卒

挺套路的博弈论,实际上就是 Game on GraphGame on Graph,但是考场上多测没清空挂了。寄。

并且 image

不过 ABC 那个官方题解好像给的是 \(O(m \log n)\) 的做法,放这题是过不去的啦x

首先显然三个棋子压状态大概是 \(10^6\) 级别的,多测 \(T=10\),那么猜测是一个 \(O(Tn^6)\) 的做法。

直接暴搜索出所有的状态,然后建图出来,然后就跟上面那个题一模一样了。

具体来说,考虑博弈 DP。

  • 若一个点没有出边,那么它为必败态;
  • 若一个点的出边中有一个必败态,那么它为必胜态;
  • 若一个点的出边中都是必胜态,那么它为必败态;
  • 若一个点的出边中没有必败态,且存在平局态,那么它为平局态。

平局态实际上就是出现环的情况。考虑类似于拓扑排序的做这个东西,根据上面的规则直接跑即可。

记录最小 / 最大步数可以在拓扑的时候同时进行,具体就是给必胜态和必败态加一个优先级,这样必胜态从所有必败态的出边中找一个最小值,必败态从所有出边找一个最大值,优先计算必败态的答案即可。

关于状态数:首先根据奇偶性,每个状态作为先手还是后手是确定的,而相同的两个红棋是可以互相交换的,两个状态相同,可以压缩成一个状态。这样状态数上界为 \(5 \times 10^5\),可以跑过去。民间数据好像不考虑相互交换也可以跑过去,官方数据不知道会怎样。

#include <bits/stdc++.h>
using namespace std;
const int MAXN = 2000005, V = 2000000;
int T;
int n, m;
char s[14][14];
#define forGraph(u, v) for (int i = fst[u], v = to[i]; i; i = nxt[i], v = to[i])
bool vis[MAXN];
int type[MAXN]; // 0: undetermined 1: lose 2: win
struct Graph {
    int fst[MAXN], nxt[8 * MAXN], to[8 * MAXN], tot;
    int q1[MAXN], q2[MAXN], q1h, q1t, q2h, q2t;
    int deg[MAXN];
    int f[MAXN], g[MAXN];
    inline void Add(int u, int v) {
        add(v, u);
        deg[u]++;
    }
    inline void clear() {
        for (int i = 0; i < V; i++) 
            fst[i] = 0;
        tot = 0;
    }
    inline void add(int u, int v) {
        to[++tot] = v, nxt[tot] = fst[u], fst[u] = tot;
    }
    inline void topo() {
        q1h = 0, q1t = 1;
        q2h = 0, q2t = 1;
        for (int i = 0; i < V; i++) if (vis[i]) {
            if (!deg[i]) {
                type[i] = 1, q1[++q1h] = i;
            }
        }
        while (q1h >= q1t || q2h >= q2t) {
            if (q1h >= q1t) {
                int u = q1[q1t++];
                forGraph(u, v) if (!type[v]) { // not determined
                    type[v] = 2;
                    f[v] = f[u] + 1;
                    q2[++q2h] = v;
                } else if (type[v] == 2) {
                    f[v] = min(f[v], f[u] + 1);
                }
            } else {
                int u = q2[q2t++];
                forGraph(u, v) if (!type[v]) { // not determined
                    deg[v]--;
                    g[v] = max(g[v], f[u] + 1);
                    if (!deg[v]) {
                        type[v] = 1;
                        q1[++q1h] = v;
                        f[v] = g[v];
                    }
                }
            }
        }
    }
} g;

int id(int ax, int ay, int bx, int by, int cx, int cy, bool f) {
    if (make_pair(bx, by) > make_pair(cx, cy)) swap(bx, cx), swap(by, cy); 
    return ((((((ax - 1) * 10 + ay - 1) * 10 + bx - 1) * 10 + by - 1) * 10 + cx - 1) * 10 + cy - 1) + f * 1000000;
}
const vector<pair<int, int>> ma = {{0, 1}, {0, -1}, {-1, 0}};
const vector<pair<int, int>> mb = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
int dfs(int ax, int ay, int bx, int by, int cx, int cy, bool f) {
    int S = id(ax, ay, bx, by, cx, cy, f);
    if (vis[S]) return S;
    vis[S] = 1;
    if ((ax == bx && ay == by) || (ax == cx && ay == cy) || ax == 1) {
        return S;
    }
    if (f) {
        // move b
        for (auto &p : mb) {
            int nx = bx + p.first, ny = by + p.second;
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && 
                    s[nx][ny] != '#' && !(nx == cx && ny == cy)) {
                int T = dfs(ax, ay, nx, ny, cx, cy, 0);
                g.Add(S, T);
            }
        }
        // move c
        for (auto &p : mb) {
            int nx = cx + p.first, ny = cy + p.second;
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && 
                    s[nx][ny] != '#' && !(nx == bx && ny == by)) {
                int T = dfs(ax, ay, bx, by, nx, ny, 0);
                g.Add(S, T);
            }
        }
    } else {
        // move a
        for (auto &p : ma) {
            int nx = ax + p.first, ny = ay + p.second;
            if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && 
                    s[nx][ny] != '#') {
                int T = dfs(nx, ny, bx, by, cx, cy, 1);
                g.Add(S, T);
            }
        }
    }
    return S;
}
int main() {
    scanf("%*d%d", &T);
    while (T--) {
        scanf("%d%d", &n, &m);
        for (int i = 1; i <= n; i++) {
            scanf("%s", s[i] + 1);
        }
        int ax, ay, bx = 0, by, cx, cy;
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= m; j++) {
                if (s[i][j] == 'X') ax = i, ay = j;
                if (s[i][j] == 'O') {
                    if (!bx) bx = i, by = j;
                    else cx = i, cy = j;
                }
            }
        }
        g.clear();
        for (int i = 0; i < V; i++) {
            vis[i] = 0, type[i] = 0;
            g.deg[i] = 0;
            g.f[i] = 0;
            g.g[i] = 0;
        }
        dfs(ax, ay, bx, by, cx, cy, 1);
        g.topo();
        int S = id(ax, ay, bx, by, cx, cy, 1);
        if (!type[S]) {
            printf("Tie\n");
            continue;
        }
        if (type[S] == 1) {
            printf("Black %d\n", g.f[S]);
        } else {
            printf("Red %d\n", g.f[S]);
        }
    }
    return 0;
}
posted @ 2023-04-10 12:00  APJifengc  阅读(148)  评论(0编辑  收藏  举报