Chess (SG博弈+状压)

原题:hdu 5724

题意:

有n行棋盘 , 每行20列 , 你可以选择一行进行操作 , 选择一个棋子移动到右边的第一个空位 , 不能操作的人lost

解析:

用打表预处理SG函数 , 注意vis只需要50就可以了(我不小心开了10000一直TLE , QAQ) , 最后异或一下为0必输不为0必胜

#include<bits/stdc++.h>
using namespace std;
int read(){ int ans=0; char last=' ',ch=getchar();
while(ch<'0' || ch>'9')last=ch,ch=getchar();
while(ch>='0' && ch<='9')ans=ans*10+ch-'0',ch=getchar();
if(last=='-')ans=-ans; return ans;
}

const int N=(1<<20)-1;

int sg[N+2];
bool vis[50];

void init(){
    memset(sg,0,sizeof(sg));
    for(int i=2;i<=N;i++){
        memset(vis,0,sizeof(vis));

        int x=i;
        int bit[22],now=0;//先存下可以节省时间
        while(x){
            bit[++now]=x%2;
            x/=2;
        }

        int last=-1;
        for(int j=1;j<=now;j++){
            if(bit[j]){
                if(last!=-1)
                    vis[sg[i-(1<<(j-1))+(1<<(last-1))]]=1;
            }
            else last=j;
        }
        for(int j=0;;j++){
            if(!vis[j]){sg[i]=j;break;}
        }
    }
}

int main(){
    //freopen("in.in","r",stdin);
    //freopen("out.out","w",stdout);
    init();
    int t=read();
    while(t--){
        int n=read();
        int A=0;
        while(n--){
            int m=read();
            int x=0;
            while(m--){
                int tmp=read();
                x+=1<<(20-tmp);
            }
            A^=sg[x];
        }
        if(A==0)printf("NO\n");
        else printf("YES\n");
    }
}

猜你喜欢

转载自blog.csdn.net/jk_chen_acmer/article/details/82146213