考虑用 ( 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;
}