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");
        }
    }
}
时间: 2024-11-04 22:43:05

hdu 5724 Chess 博弈的相关文章

HDU 5724 Chess(国际象棋)

HDU 5724 Chess(国际象棋) Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Description 题目描述 Alice and Bob are playing a special chess game on an n × 20 chessboard. There are several chesses on the chessboard. They can mo

HDU 5724 Chess(SG函数)

Chess Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)Total Submission(s): 2605    Accepted Submission(s): 1092 Problem Description Alice and Bob are playing a special chess game on an n × 20 chessboard. There are s

HDU 5724 Chess(博弈论)

[题目链接] http://acm.hdu.edu.cn/showproblem.php?pid=5724 [题目大意] 给出一个n行,每行有20格的棋盘,棋盘上有一些棋子,每次操作可以选择其中一个棋子,将其移至最左端的空位,两个人轮流操作,无法操作者输,判断游戏胜负. [题解] 首先对于单行20格的游戏,这是一个NIM游戏,将20格的情况状态压缩,对于每种情况递归求其mex集合,计算其sg值,sg值为0的状态为必败态. 而对于可以拆分为多组NIM游戏的游戏,其sg值为拆分出的多组游戏的sg值的

HDU 5724 Chess

因为一行最多只有20个数,也就是说只有(1<<20)种状态,向右移动表示小的数推向了大的数.可以用SG函数预处理出所有情况.然后把每一行的SG函数值异或一下,非零则必胜,否则输. #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> #include<vector> #include<map> #include<set> #

hdu 3032(博弈sg函数)

题意:与原来基本的尼姆博弈不同的是,可以将一堆石子分成两堆石子也算一步操作,其它的都是一样的. 分析:由于石子的堆数和每一堆石子的数量都很大,所以肯定不能用搜索去求sg函数,现在我们只能通过找规律的办法求得sg的规律. 通过打表找规律可以得到如下规律:if(x%4==0) sg[x]=x-1; if(x%4==1||x%4==2) sg[x]=x; if(x%4==3) sg[x] = x+1. 打表代码: #include<iostream> #include<cstdio> #

hdu 4832 Chess(dp)

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 193    Accepted Submission(s): 59 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘上的走法遵循十字路线

HDU 4832 Chess (DP)

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 24    Accepted Submission(s): 10 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘上的走法遵循十字路线.

HDU 4832 Chess 排列组合 DP

Chess Time Limit: 6000/3000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 351    Accepted Submission(s): 124 Problem Description 小度和小良最近又迷上了下棋.棋盘一共有N行M列,我们可以把左上角的格子定为(1,1),右下角的格子定为(N,M).在他们的规则中,"王"在棋盘 上的走法遵循十字

HDU 4832 Chess

同样是百度之星的题目.刚开始看题目,觉得这是一道搜索的题,于是就萌生了找题解的想法.一开始就没有斗志,当然不会做出这道题的啦. 可是看完题解恍然大悟,原来是DP,而且很简单的一道DP.再一次失败,说明了看题解真的不是一个好习惯.我要改! 我要改!! 其实基本的思想就是把这个二维移动分开,变成一维的移动,最后加上组合数就OK了. 下面的是代码,虽然是自己敲的,但是还是剽窃过来的.... #include <iostream> #include <cstdio> #include &l