題目分析
這題好喵啊。
如果沒有“任意修改相鄰城市的稅收”這個操作,就是個美滋滋的Nim遊戲。
接下來的思路就很巧妙了,將城市分組。所有出度爲0的點爲第0組,其他點爲第mex(其可達節點的組編號)組。
這個有兩個性質:
- 同一組不存在一對節點,,滿足存在邊。
- 對於第組中的任意一個點,它可以到達第到第組,每一組中的至少一點。
若每一組的異或和都爲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;
}