冬令营纳新一百的石子游戏(尼姆博弈论)

链接:https://ac.nowcoder.com/acm/contest/4010/C
来源:牛客网
 

题目描述

纳新一百和乱得尬得在玩取石子的游戏。他们一共有 N{N}N 堆石子,第 i{i}i 堆有 aia_{i}ai​ 颗石子(若 ai=0a_{i}=0ai​=0 则表示这是一堆空石子堆)。
纳新一百和乱得尬得轮流进行游戏,纳新一百先手。轮到某个人时,他需要选择一堆非空的石子堆,并拿走任意数量的石子。如果不存在一堆非空的石子堆,则轮到的人输掉游戏。纳新一百想要知道,他的第一轮操作有多少种不同的取法能够保证他最后取得游戏的胜利。假设两个人都是用最优策略在玩游戏,两种操作方式视为不同当且仅当两种方式选取的石子堆的序号不同或取走的石子数量不同。
为了增加趣味性,纳新一百和乱得尬得决定对前i{i}i堆石子都玩一次游戏,两次游戏相互独立,也就是说,每开始一个新的游戏,石子堆都会被复原。
现在,纳新一百想要知道每一次游戏中,他能够取得胜利的第一轮操作方案数。

输入描述:

第一行一个正整数 N(1⩽N⩽105)N(1\leqslant N \leqslant 10^{5})N(1⩽N⩽105),表示石子堆数。
第二行 N{N}N 个数,表示ai(0⩽ai<260)a_{i}(0\leqslant a_{i}<2^{60})ai​(0⩽ai​<260)。

输出描述:

N{N}N 行,每行一个整数。第 i{i}i 行的整数表示用前 i{i}i 堆石子玩游戏时,纳新一百在第一轮有多少种操作方式保证自己能获得胜利。如果纳新一百无论如何都不可能赢得游戏,输出 0{0}0。

示例1

输入

复制6 0 0 2 8 7 0

6
0 0 2 8 7 0

输出

复制0 0 1 1 1 1

0
0
1
1
1
1

 

题解:根据尼姆博弈可以知道异或和为0就是可以的。然后题目中累计个个2进制位的异或和,通过公式判断异或的结果,以二进制来处理。。。

代码:

#include

using namespace std;

#define next next1

#define ll long long

 

int b[80];

 

void insert(ll x)

{

    for (int i=59;i>=0;i--)

    {

        if (x&(1LL<

    }

}

 

int query(ll x)

{

    int p=-1;

    for (int i=59;i>=0;i--)

    {

        if (x&(1LL<

        {

            return b[i];

        }

    }

    return 0;

}

 

int n;

 

int main()

{

    scanf("%d",&n);

    ll x=0;

    for (int i=1;i<=n;i++)

    {

         ll p;

         scanf("%lld",&p);

         insert(p);

         x^=p;

         printf("%d\n",query(x));

    }

    return 0;

}

你可能感兴趣的:(冬令营纳新一百的石子游戏(尼姆博弈论))