• 1149E


    博弈论

    如果没有修改后继城市这个操作,就是一个$nim$游戏

    现在将整个图的$sg$函数求出 把所有点按$sg$函数分类 设一类点的编号为$sg$函数值 每一类点有以下性质

    1.这类点之间互相没有直接连边

    2.这类点能到达所有编号小于该类点的集合中的至少一点

    以上根据$sg$函数性质可以直接推出

    设每类点的$sum$为所有$h$的异或和 根据$nim$游戏 如果所有类的$sum$都为$0$ 那么先手必输 因为如果先手修改某个点的$h$以及后继 那么同类点中肯定存在某个点可以通过同样的操作使得$sum$重新变回$0$ 直到不可操作

    如果$sum$存在不为$0$ 那么先手必胜 找到编号最大的那类点中某点 修改该点及后继点的$h$使得$sum$全部为$0$即可

    #include <bits/stdc++.h>
    using namespace std;
    const int maxn = 2e5 + 5;
    int n, m;
    int h[maxn], in[maxn], q[maxn], sg[maxn], sum[maxn], vis[maxn];
    vector<int> G[maxn];
    int main() {
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i) scanf("%d", &h[i]);
        for(int i = 1; i <= m; ++i) {
            int u, v; scanf("%d%d", &u, &v);
            G[u].push_back(v);
            ++in[v];
        }
        int l = 1, r = 0;
        for(int i = 1; i <= n; ++i) if(!in[i]) q[++r] = i;
        while(l <= r) {
            int u = q[l++];
            for(int i = 0; i < G[u].size(); ++i) {
                int v = G[u][i];
                if(!--in[v]) q[++r] = v;
            }
        }
        for(int i = n; i; --i) {
            int u = q[i];
            for(int j = 0; j < G[u].size(); ++j) {
                int v = G[u][j];
                vis[sg[v]] = 1;
            }
            for(; vis[sg[u]]; ++sg[u]);
            for(int j = 0; j < G[u].size(); ++j) {
                int v = G[u][j];
                vis[sg[v]] = 0;
            }
        }
        for(int i = 1; i <= n; ++i) sum[sg[i]] ^= h[i];
        int p = -1;
        for(int i = n; ~i; --i) if(sum[i]) {
            p = i;
            break;
        } 
        if(p == -1) {
            puts("LOSE");
            return 0;
        }
        puts("WIN");
        for(int i = 1; i <= n; ++i) if(sg[i] == p) {
            if((sum[p] ^ h[i]) > h[i]) continue;
            h[i] ^= sum[p]; 
            for(int j = 0; j < G[i].size(); ++j) {
                int v = G[i][j];
                h[v] ^= sum[sg[v]];
                sum[sg[v]] = 0;
            }
            break;
        }
        for(int i = 1; i <= n; ++i) printf("%d ", h[i]);
        return 0;
    } 
    View Code
  • 相关阅读:
    zoj 3627 Treasure Hunt II (贪心)
    1028
    DB2数据库性能优化介绍
    Python之美[从菜鸟到高手]--深刻理解原类(metaclass)
    Java和C++中多态的实现方式
    汉语-词语-停留:百科
    汉语-词语-体会:百科
    汉语-词语-味道:百科
    笔记-生活-饮食:香料妙用
    汉语-词语-香料:百科
  • 原文地址:https://www.cnblogs.com/19992147orz/p/11561823.html
Copyright © 2020-2023  润新知