• codechef Table Game(博弈)


    题意

    题目链接

    很难概括。。

    Sol

    (因为比赛还没结束,所以下面讲的可能是“非官方”“正解”)

    maya这题我前前后后 断断续续的做了一个星期才A掉。CC一场challenge出两道打表题可有点过分了啊。。

    首先考虑暴力怎么打,我们把给出的初始行列的01取反,这样$0$的时候对应的是必胜态,$1$对应的是必败态。

    然后按博弈论的定义推,$(i, j)$若是必胜态,那么至少有$(i - 1, j)$是必败态 或者 $(i, j - 1)$是必败态。

    然后暴力枚举一遍就行了,复杂度$O(NM)$

    接下来的操作就比较神仙了,,打表 或 直接观察式子可得,若第$(i, j)$个点是必败点,那么它所在的对角线往后的点,都是必败点!

    这样我们就把状态降到了$2 * M$

    那最开始的必败点怎么求呢?

    直觉告诉我们 稍加证明不难得到,这种点一定是出现在前两行 或者前两列。

    然后就做完了。

    暴力推前两行 前两列即可。

    保险起见我推了三行三列。

    #include<cstdio>
    #include<cstring>
    #include<vector>
    #define LL long long 
    using namespace std;
    const int MAXN = 1e5 + 10;
    inline LL read() {
        char c = getchar(); LL x = 0, f = 1;
        while(c < '0' || c > '9') {if(c == '-') f = -1; c = getchar();}
        while(c >= '0' && c <= '9') x = x * 10 + c - '0', c = getchar();
        return x * f;
    }
    int T;
    int a[4][MAXN], b[MAXN][4], N, M, f[MAXN], g[MAXN];
    char A[MAXN], B[MAXN];
    int main() { 
    //-    freopen("a.out", "w", stdout);
        int T = read();
        while(T--) {
            scanf("%s", A + 1);
            scanf("%s", B + 1);
            M = strlen(A + 1);
            N = strlen(B + 1);
            for(int i = 1; i <= M; i++) a[0][i] = (A[i] == '1' ? 0 : 1);
            for(int i = 1; i <= 3; i++) a[i][0] = (B[i] == '1' ? 0 : 1);
            
            for(int i = 1; i <= 3; i++) b[0][i] = (A[i] == '1' ? 0 : 1);
            for(int i = 1; i <= N; i++) b[i][0] = (B[i] == '1' ? 0 : 1);
            
            memset(f, 0x7f, sizeof(f));
            memset(g, 0x7f, sizeof(g));
            
            for(int i = 1; i <= 3; i++) {
                for(int j = 1; j <= M; j++) {
                    if(a[i - 1][j] == 1 || a[i][j - 1] == 1) a[i][j] = 0;//能到达必败节点的 
                    else a[i][j] = 1;
                    if(a[i][j] == 1) f[j - i + 1] = min(f[j - i + 1], i);
                }
            }
            
            for(int i = 1; i <= N; i++) {
                for(int j = 1; j <= 3; j++) {
                    if(b[i - 1][j] == 1 || b[i][j - 1] == 1) b[i][j] = 0;
                    else b[i][j] = 1;
                    if(b[i][j] == 1) g[i - j + 1] = min(g[i - j + 1], j);
                }
            }
            vector<int> ans;
            int Q = read();
            while(Q--) {
                int x = read(), y = read();
                int dy = y - x + 1,
                    dx = x - y + 1;
                if(dy >= 1) {
                    if(x >= f[dy]) ans.push_back(0);
                    else ans.push_back(1); 
                } else {
                    if(y >= g[dx]) ans.push_back(0);
                    else ans.push_back(1);
                }
            }
            for(int i = 0; i < ans.size(); i++) printf("%d", ans[i]);        
            puts("");
        }
    
        return 0;
    }
    /*
    2
    101
    01
    6
    1 1
    1 2
    1 3
    2 1
    2 2
    2 3
    101
    01
    6
    1 1
    1 2
    1 3
    2 1
    2 2
    2 3
    */
  • 相关阅读:
    C# IEnumerable 和 IEnumerator接口浅析
    SQLite笔记
    命令行工具osql.exe使用
    2016年年终工作总结
    c# Json 自定义类作为字典键时,序列化和反序列化的处理方法
    多线程随笔
    常见异步机制分析
    SQL 通过syscolumns.xtype动态查找指定数据类型字段所包含的数据
    SQL 删除索引错误
    SQL 实用函数
  • 原文地址:https://www.cnblogs.com/zwfymqz/p/9656189.html
Copyright © 2020-2023  润新知