正文
ZOJ 3964 NIM变形
小程序:扫一扫查出行
【扫一扫了解最新限行尾号】
复制小程序
【扫一扫了解最新限行尾号】
复制小程序
LINK
题意: n堆石子,Alice 和 Bob 轮流取石子,谁不能再取或被对方取完为败。但是对于alice拥有限制:b=0此堆正常无限制;b=1此堆Alice只能取奇数个石子;b=2只能取偶数个石子
思路: 一看就知道是个NIM的变形题,现在想做这题的思路应当是讨论奇偶个石子且分别在奇数偶数限制下的胜负状况。
很容易能看出当有两堆以上的限制堆时(a=1 b=1不算限制)显然是Alice必败,这是最重要的条件,可以避免大量的推导。
再者讨论b=1的情况:
如果a为偶数,显然该堆可被Bob保证不被Alice一次拿完——直至剩下1颗,此时必定是Bob的回合。
如果a为奇数,如果Alice不取完该堆,Bob可以使该堆变为偶数堆,也可以直接取完,显然对于前者相当于转换到a为偶数的情况,对于后者,相当于不存在该堆,B可控制A的先后手,故A必败。那么如果Alice取完,相当于先后手交换。
最后讨论b=2的情况:
如果a为偶数,如果Alice不取完该堆,Bob可以使该堆变为奇数堆,也可以直接取完,类似于上种情况。先后手互换。
如果a为奇数,那么因为Alice不能取而必败
抱怨一下比赛的时候交了两发WA也没过,也没考虑这么仔细,先后手交换的本应该另加讨论的,我却直接异或了2...
#include <bits/stdc++.h>
#define LL long long
#define PII pair
#define MP(x, y) make_pair((x),(y))
#define fi first
#define se second
#define PB(x) push_back((x))
#define MMG(x) memset((x), -1,sizeof(x))
#define MMF(x) memset((x),0,sizeof(x))
#define MMI(x) memset((x), INF, sizeof(x))
using namespace std;
const int N = 1e5+5;
int a[N], b[N];
int main()
{
int T, n;
scanf("%d", &T);
while(T--)
{
scanf("%d", &n);
int cnt = 0;
int ans = 0;
int flag = 0;
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]); for(int i = 1; i <= n; ++i)
{
scanf("%d", &b[i]);
if(b[i] == 1 && a[i] == 1)
ans ^= 1;
else if(b[i] == 1)
{
cnt++;
if(cnt > 1)//有两堆以上限制先手必败
continue;
flag = 1;//必定先后手互换
if(a[i] % 2 == 0) //留1颗
ans ^= 1;
//else ans ^= 0;//先手取完
}
if(b[i] == 2)
{
cnt++;
if(cnt > 1)
continue;
if(a[i] % 2 == 0) //取完,互换先后手
flag = 1;
if(a[i] % 2 == 1) //先手必败 必定会留下一颗
cnt++;
}
if(b[i] == 0)
ans ^= a[i];
}
if(cnt >= 2)
printf("Bob\n");
else if(cnt == 1)
{
if(ans && flag)
printf("Bob\n");
else
printf("Alice\n");
}
else
{
if(ans)
printf("Alice\n");
else
printf("Bob\n");
}
}
return 0;
}