hdu 5724 Chess 博弈

题目链接

 

一个n行20列的棋盘。 每一行有若干个棋子。 两人轮流操作, 每人每次可以将一个棋子向右移动一个位置, 如果它右边有一个棋子, 就跳过这个棋子, 如果有若干个棋子, 就将这若干个都跳过。 但是棋子不能移出边界。

如果没有办法移动了, 就算输。 问你先走的能否赢。

 

只有20列, 所以预处理出所有状态的sg值。 然后直接异或就好了。

然后sg[(1<<20)-1] = 0, 这是必输态, 其他的都可以dfs出来, 具体看代码。

 

#include <bits/stdc++.h>

using namespace std;
#define pb(x) push_back(x)
#define ll long long
#define mk(x, y) make_pair(x, y)
#define lson l, m, rt<<1
#define mem(a) memset(a, 0, sizeof(a))
#define rson m+1, r, rt<<11
#define mem1(a) memset(a, -1, sizeof(a))
#define mem2(a) memset(a, 0x3f, sizeof(a))
#define rep(i, n, a) for(int i = a; i<n; i++)
#define fi first
#define se second
typedef pair<int, int> pll;
const double PI = acos(-1.0);
const double eps = 1e-8;
const int mod = 1e9+7;
const int inf = 1061109567;
const int dir[][2] = { {-1, 0}, {1, 0}, {0, -1}, {0, 1} };
int sg[1<<22];
int mex(int x)
{
    if(~sg[x])
        return x;
    bool vis[20];
    memset(vis, false, sizeof(vis));
    for(int i = 0; i < 20; i++) {
        if(((1<<i)&x)==0 && ((1<<(i+1))&x)) {
            int j;
            for(j = i + 2; j < 20; j++) {
                if(!(1<<j&x))
                    break;
            }
            for(int k = i+1; k <= j; k++) {
                int sta = x^(1<<i)^(1<<k);
                if(sta>=(1<<20))
                    break;
                mex(sta);
                vis[sg[sta]] = 1;
            }
        }
    }
    for(int i = 0; i < 20; i++)
        if(!vis[i])
            return sg[x] = i;
}
void init()
{
    mem1(sg);
    sg[(1<<20)-1] = 0;
    for(int i = 0; i < (1<<20); i++) {
        if(sg[i] == -1) {
            mex(i);
        }
    }
}
int main()
{
    init();
    int t, n, m, x;
    cin>>t;
    while(t--) {
        cin>>n;
        int ans = 0;
        for(int i = 0; i < n; i++) {
            scanf("%d", &m);
            int sta = 0;
            while(m--) {
                scanf("%d", &x);
                sta |= (1<<(20-x));
            }
            ans ^= sg[sta];
        }
        if(ans) {
            puts("YES");
        } else {
            puts("NO");
        }
    }
}

 

转载于:https://www.cnblogs.com/yohaha/p/5689958.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值