题解 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;
}