题解 CF1149E 【Election Promises】

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

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

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

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

\[\large\underset{\text{SG}(x)=w_k}{\text{xor}}\ v_x=0 \]

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

考虑如何构造方案。先找到最大的不满足异或和为 \(0\)\(k\),然后选一个 \(\text{SG}\) 值为 \(w_k\) 的点 \(x\),将其点权异或上 \(w_k\) 的异或和,使 \(w_k\) 的异或和变为 \(0\),这里要保证异或后得到的值比原先的值小。根据 \(\text{mex}\) 的定义,对于 \(\forall k \in [0,k-1]\),点 \(x\) 都可以到达 \(\text{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;
}
posted @ 2020-09-24 21:19  lhm_liu  阅读(259)  评论(0编辑  收藏  举报