把每个点上的权值v当成v个子游戏。最后我们用sg定理合并即可。
如何求出一个点上的子游戏的sg值?
注意到一个点的后继状态很少,枚举再求个mex即可。
#include<iostream>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
int n,m;
#define V 105
#define E 1505
int bitscount[200010];
int head[V],v[E],nxt[E],out[V],in[V],tot=0;
bool vis[V];
int K[V];
int sg[V];
bool ap[200010];
int sum[200010];
int num[200010];
int lowbit(int x){return x&(-x);}
void solve(int u){
vis[u]=true;
for(int i=head[u];i;i=nxt[i])
if(!vis[v[i]])solve(v[i]);
if(!out[u])sg[u]=0;
else{
sum[0]=0;
for(int i=head[u],t=0;i;i=nxt[i],++t)num[1<<t]=sg[v[i]];
for(int i=1;i<(1<<out[u]);++i)
sum[i]=num[lowbit(i)]^sum[i-lowbit(i)];
for(int i=0;i<(1<<out[u]);++i)
if(K[u]>=bitscount[i]&&(K[u]-bitscount[i])%2==0)ap[sum[i]]=true;
int Ans=0;
while(ap[Ans])Ans++;
sg[u]=Ans;
for(int i=0;i<(1<<out[u]);++i)
if(K[u]>=bitscount[i]&&(K[u]-bitscount[i])%2==0)ap[sum[i]]=false;
}
}
int main(){
for(register int i=0;i<(1<<17);++i)bitscount[i]=bitscount[i>>1]+(i&1);
int T;
scanf("%d",&T);
for(register int tt=1;tt<=T;++tt){
printf("Game#%d:\n",tt);
memset(head,0,sizeof(head));tot=0;
memset(out,0,sizeof(out));
memset(in,0,sizeof(in));
memset(vis,false,sizeof(vis));
scanf("%d%d",&n,&m);
int s,e;
for(register int i=1;i<=m;++i){
scanf("%d%d",&s,&e);
s++;e++;
tot++;v[tot]=e;nxt[tot]=head[s];head[s]=tot;
out[s]++;in[e]++;
}
for(register int i=1;i<=n;++i)scanf("%d",&K[i]);
for(register int i=1;i<=n;++i)
if(!in[i])solve(i);
int R;
scanf("%d",&R);
for(register int t=1;t<=R;++t){
int x;
int Zjr=0;
for(register int i=1;i<=n;++i){
scanf("%d",&x);
if(x&1)Zjr^=sg[i];
}
if(Zjr)printf("Round#%d: WINNING\n",t);
else printf("Round#%d: LOSING\n",t);
}
puts("");
}
return 0;
}