• 题解 CF1149E 【Election Promises】


    考虑用 ( ext{SG}) 函数来解决本题,因为降低一个点的点权后,可以任意修改该点的后继节点的点权,所以一个状态可以到达的状态是有无穷多个的。

    (w_k)(k) 阶无穷大。若一个节点没有出边,则其 ( ext{SG}) 值为 (w_0)。对于无穷大,( ext{SG}) 值也是满足 ( ext{mex}) 运算的,即若一个节点的后继节点的 ( ext{SG}) 值出现了 (w_0,w_1,dots,w_{k-1}),则该点的 ( ext{SG}) 值为 (w_k)

    因为图是 (DAG),所以可以用拓扑排序处理出 ( ext{SG}) 值。

    对于一个状态,若对于 (forall k in [0,n]),都满足:

    [largeunderset{ ext{SG}(x)=w_k}{ ext{xor}} v_x=0 ]

    则该状态为必败状态。所以先手要将自己当前的状态转化为每个无穷大的异或和都为 (0) 的状态给后手。

    考虑如何构造方案。先找到最大的不满足异或和为 (0)(k),然后选一个 ( ext{SG}) 值为 (w_k) 的点 (x),将其点权异或上 (w_k) 的异或和,使 (w_k) 的异或和变为 (0),这里要保证异或后得到的值比原先的值小。根据 ( ext{mex}) 的定义,对于 (forall k in [0,k-1]),点 (x) 都可以到达 ( ext{SG}) 值为 (w_k) 的至少一个点,对于这些点若其对应的无穷大的异或和不为 (0),用同样的方法将其调整为 (0) 即可。

    #include<bits/stdc++.h>
    #define maxn 200010
    using namespace std;
    template<typename T> inline void read(T &x)
    {
        x=0;char c=getchar();bool flag=false;
        while(!isdigit(c)){if(c=='-')flag=true;c=getchar();}
        while(isdigit(c)){x=(x<<1)+(x<<3)+(c^48);c=getchar();}
        if(flag)x=-x;
    }
    int n,m;
    int v[maxn],w[maxn],s[maxn],d[maxn],tag[maxn];
    vector<int> ve[maxn];
    struct edge
    {
        int to,nxt;
    }e[maxn];
    int head[maxn],edge_cnt;
    void add(int from,int to)
    {
        e[++edge_cnt]={to,head[from]},head[from]=edge_cnt;
    }
    void topo()
    {
        queue<int> q;
        for(int i=1;i<=n;++i)
            if(!d[i])
                q.push(i);
        while(!q.empty())
        {
            int x=q.front();
            q.pop();
            for(int i=head[x];i;i=e[i].nxt)
                if(--d[e[i].to]==0)
                    q.push(e[i].to);
            for(int i=0;i<ve[x].size();++i) tag[w[ve[x][i]]]=x;
            while(tag[w[x]]==x) w[x]++;
            s[w[x]]^=v[x];
        }
    }
    int main()
    {
        read(n),read(m);
        for(int i=1;i<=n;++i) read(v[i]);
        for(int i=1;i<=m;++i)
        {
            int x,y;
            read(x),read(y);
            ve[x].push_back(y),add(y,x),d[x]++;
        }
        topo();
        for(int i=n;i>=0;--i)
        {
            if(!s[i]) continue;
            int pos;
            for(int j=1;j<=n;++j)
                if(w[j]==i&&v[j]>(v[j]^s[i]))
                    pos=j;
            v[pos]^=s[i];
            for(int j=0;j<ve[pos].size();++j)
            {
                int x=ve[pos][j];
                v[x]^=s[w[x]],s[w[x]]=0;
            }
            puts("WIN");
            for(int j=1;j<=n;++j) printf("%d ",v[j]);
            return 0;
        }
        puts("LOSE");
        return 0;
    }
    
  • 相关阅读:
    葵花宝典,参考学习网站收藏
    安卓工具
    马帮
    C89:vs输出调试信息
    OSG:中级篇 拖拽器类
    OSG:幼儿园篇 第六章 碰撞检测类
    OSG:幼儿园篇 第三章 节点坐标变换类
    OSG:幼儿园篇 第五章 界面交互类
    C++11:智能指针
    OSG:幼儿园篇 第四章 节点回调类
  • 原文地址:https://www.cnblogs.com/lhm-/p/13726738.html
Copyright © 2020-2023  润新知