题目分析
这题好喵啊。
如果没有“任意修改相邻城市的税收”这个操作,就是个美滋滋的Nim游戏。
接下来的思路就很巧妙了,将城市分组。所有出度为0的点为第0组,其他点为第mex(其可达节点的组编号)组。
这个有两个性质:
- 同一组不存在一对节点xxx,yyy,满足存在边(x,y)(x,y)(x,y)。
- 对于第ttt组中的任意一个点,它可以到达第000到第ttt组,每一组中的至少一点。
若每一组的异或和都为0,则WA党必败,否则必胜。
第一步的策略就是,找到编号最大的,异或和不为0的组,找到其中一个可以通过减少税收使得改组异或和变为0的点,通过在这个点上拉票,修改其相邻城市的税收,使得每一组的异或和都变为0。
代码
#include<bits/stdc++.h>
using namespace std;
#define RI register int
int read() {
int q=0;char ch=' ';
while(ch<'0'||ch>'9') ch=getchar();
while(ch>='0'&&ch<='9') q=q*10+ch-'0',ch=getchar();
return q;
}
const int N=200005;
int n,m,tot,cnt;
int h[N],ne[N],to[N],w[N],du[N],stk[N],seq[N],id[N],vis[N],sg[N];
void add(int x,int y) {to[++tot]=y,ne[tot]=h[x],h[x]=tot;}
void toposort() {
int top=0,js=0;
for(RI i=1;i<=n;++i) if(!du[i]) stk[++top]=i;
while(top) {
int x=stk[top];--top,seq[++js]=x;
for(RI i=h[x];i;i=ne[i]) {
--du[to[i]];
if(!du[to[i]]) stk[++top]=to[i];
}
}
for(RI i=n;i>=1;--i) {
int x=seq[i];
for(RI j=h[x];j;j=ne[j]) ++vis[id[to[j]]];
while(vis[id[x]]) ++id[x];
if(id[x]>cnt) cnt=id[x];
for(RI j=h[x];j;j=ne[j]) --vis[id[to[j]]];
}
}
int main()
{
int x,y;
n=read(),m=read();
for(RI i=1;i<=n;++i) w[i]=read();
for(RI i=1;i<=m;++i) x=read(),y=read(),add(x,y),++du[y];
toposort();
for(RI i=1;i<=n;++i) sg[id[i]]^=w[i];
int flag=-1;
for(RI i=0;i<=cnt;++i) if(sg[i]) flag=i;
if(flag==-1) {puts("LOSE");return 0;}
puts("WIN");
for(RI i=1;i<=n;++i) if(id[i]==flag) {
if((sg[id[i]]^w[i])>w[i]) continue;
w[i]^=sg[id[i]],sg[id[i]]=0;
for(RI j=h[i];j;j=ne[j])
w[to[j]]^=sg[id[to[j]]],sg[id[to[j]]]=0;
}
for(RI i=1;i<=n;++i) printf("%d ",w[i]);
puts("");
return 0;
}