题面
7-3 2C. 纳新一百的石子游戏
纳新一百和乱得尬得在玩取石子的游戏。他们一共有N堆石子,第i堆有ai颗石子(若ai=0则表示这是一堆空石子堆)。
纳新一百和乱得尬得轮流进行游戏,纳新一百先手。轮到某个人时,他需要选择一堆非空的石子堆,并拿走任意数量的石子。如果不存在一堆非空的石子堆,则轮到的人输掉游戏。纳新一百想要知道,他的第一轮操作有多少种不同的取法能够保证他最后取得游戏的胜利。假设两个人都是用最优策略在玩游戏,两种操作方式视为不同当且仅当两种方式选取的石子堆的序号不同或取走的石子数量不同。
为了增加趣味性,纳新一百和乱得尬得决定对前i堆石子都玩一次游戏,两次游戏相互独立,也就是说,每开始一个新的游戏,石子堆都会被复原。
现在,纳新一百想要知道每一次游戏中,他能够取得胜利的第一轮操作方案数。
输入格式:
第一行一个正整数(,表示石子堆数。 第二行N个数,
输出格式
N行,每行一个整数。第i行的整数表示用前i堆石子玩游戏时,纳新一百在第一轮有多少种操作方式保证自己能获得胜利。如果纳新一百无论如何都不可能赢得游戏,输出0。
输入样例:
6
0 0 2 8 7 0
输出样例:
0
0
1
1
1
1
题解
设当前异或和为x,则要找到的就是有多少堆石头y满足y>x xor y,这样就能将y变为x xor y来使得异或和为0。考虑异或和的最高的为1的二进制位,所有这一位是1的y显然都满足条件,这一位是0的都不满足条件。#include<cstring> #include<cstdio> #define RE register #define FOR(i,a,b) for(RE int i=a;i<=b;++i) #define ROF(i,a,b) for(RE int i=a;i>=b;--i) #define sc(n) scanf("%d",&n) #define ll long long using namespace std; const int maxn = 1e5 + 10; int n, w[65]; ll a[maxn], b[maxn], c[maxn]; int main() { sc(n); FOR(i, 1, n) { scanf("%lld",&a[i]); b[i] = b[i - 1] ^ a[i]; if (a[i]) FOR(j,0,60) if (a[i] & (1ll<<j))++w[j]; else if ((1ll << j) >= a[i])break; if (!b[i])c[i] = 0; else if (!a[i])c[i] = c[i - 1]; else { RE int zw; FOR(j,0,60) if (b[i] & (1ll<<j))zw = j; else if ((1ll<<j)>=b[i])break; c[i] = w[zw]; } printf("%lld ", c[i]); } return 0; }