[XSY 1149][sg函数]游戏

把每个点上的权值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;
}

猜你喜欢

转载自blog.csdn.net/ezoilearner/article/details/83067525