首页 > 其他分享 >「解题报告」P9169 [省选联考 2023] 过河卒

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

时间:2023-04-10 12:11:27浏览次数:54  
标签:10 P9169 省选 ++ int MAXN && bx 联考

挺套路的博弈论,实际上就是 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;
}

标签:10,P9169,省选,++,int,MAXN,&&,bx,联考
From: https://www.cnblogs.com/apjifengc/p/17302519.html

相关文章

  • [省选联考 2023] 染色数组 题解
    题目描述给定一个长度为\(n\)的正整数数组\(A\),其中每个数都在\(1\)到\(m\)之间,从左到右排成一排。现在要将每个数字染成红色或者绿色,我们定义一个染色方案为优秀的染色方案,当且仅当它满足:每个数\(A_{i}\)要么被染成红色,要么被染成绿色。红色的数从左到右依次严格递......
  • 联合省选2023邮寄
    Day-INFNOIP诡异的地方写挂,导致在队线附近,省选压力其实很大。Day-7模拟赛一道网络流模型建错拿到了\(-1\)的\(5\)分,一道线段树写成分块T+Wa成\(0\)分,喜提倒一。但是可以和ducati一样的排名。Day-1找了个理由请假回家。早上去跑步,将四公里跑进了16min,比较开心。......
  • [省选联考 2023] 染色数组 题解
    题目描述给定一个长度为\(n\)的正整数数组\(A\),其中每个数都在\(1\)到\(m\)之间,从左到右排成一排。现在要将每个数字染成红色或者绿色,我们定义一个染色方案为优秀的染色方案,当且仅当它满足:每个数\(A_{i}\)要么被染成红色,要么被染成绿色。红色的数从左到右依次严格递......
  • 鲜花:省选前后产生的一点想法
    想讲点废话。大概有两个想说的话题,所以拿不准标题起什么。其中一个和省选前有关。今年省选,我特意留意了一下我的心态。或者说,特意去感受了一下我的心态到底是个什么情况。在以前我是认为心态就分成两类,就是紧张与不紧张。紧张的话这场考试大概率是考不好的,不紧张的话这场考试考......
  • 2023省选总结
    Day18:30迅速看完T1,T2题面,举手上厕所思考。8:50发现T1没啥可做的,T2花约5分钟想清楚题意。9:00回来码完T1。测大样例发现全过,思考感觉不好拍,于是没写拍。开始思考T2。10:00初步想到转化成圆方树的建模,但是不很自信。思想斗争约10分钟后胡出一个证明(似乎是真的......
  • 联合省选 2023 又寄
    中寄算小寄,小寄不算寄!\(\text{Day0}\)晚上和智爷打了一个小时羽毛球,爽!\(\text{Day1}\)进场先过\(\text{T1}\),推了半天\(\text{T2}\)不会,先看看\(\text{T3}\),推了一下没有删除感觉会了,加个线段树分治有\(74+\)貌似,但是不是很好写,再看看\(\text{T2}\)再说发现看错题......
  • 联合省选 2023 游记
    当一个人开始苦苦哀求命运网开一面,将一切希望都寄托于上天之时,他就已经败了。又是绝望中充满希望,最终却平复于虚无的一次比赛。noip留下的窟窿太大了,炸到了\(113\)分,而队线却足足有\(175\text{pts}\)。很幸运,省选前好消息接连传来:省队\(8\)个人,这意味着\(\frac{1}{3......
  • NOI2023联合省选游记
    前言这次比赛去了广大附中,也是我初中最后一场比赛了吧Day-DY的由于里的太近了,住在学校里,感到惋惜。训练量有点少,不知道因该干什么,于是随便看了几个简单数学知识。譬如拉格朗日,三维计算几何。比较冷门,考试没有太大用途,只能赌一把,看看它考不考。Day1第一天早上6点20起来,酒店的......
  • 联合省选2023
    火车站显然可行当且仅当轨道连续且存在以其为对应方向端点的轨道差分判定即可,时间复杂度为\(O(n+m)\)城市建造\(G-E'\)为\(|V'|\)个连通块当且仅当\(V'\)中的点两两不连通,则:\(E'\)为\(V'\)的导出子图(\(V'\)内部的边需被删除)对于路径\(a_{0},a_{1},...,a_{k}\),若\(a_{0}......
  • 省选丢人
    考场以外的部分应该对大家没什么启发意义,摆了。本来不想写,但是发现hz的学长们都写了,再加上大家今天都没心情学东西,我就写了。day1发现机子非常好,燕大终于进步了!看T1,感觉瞎写就能过,遂瞎写,写了两分钟一遍过大样例。直接跳,闲来无事随便输了组小数据,一测,欸,挂了!ccf你坏事做尽......