HDU-3032 Nim or not Nim?
Nim or not Nim?
两个人进行博弈轮流操作,有 \(n\) 堆石子,每堆石子有 \(a_i\) 个石子,每次操作可以取一堆里的若干个石子,但至少一个,或将一堆石子分成两堆
尼姆博弈变种 打表
可以通过sg函数先打表分析每一种情况,再得出结论
\(sg[i] = mex(sg[0], sg[1],...,sg[i-1], sg[1] \bigoplus sg[i-1], sg[2] \bigoplus sg[i-2]....)\)
通过打表分析,除了被4整除的和除4余3的数字sg函数变化了以外,其余的 \(sg[i] = i\),而且变化的规律也很好找,打一打表就知道了
AC代码
#include <iostream>
#include <cstdio>
using namespace std;
const int maxn = 1e6 + 10;
int num[maxn];
int main()
{
int t;
scanf("%d", &t);
while(t--)
{
int n;
scanf("%d", &n);
for(int i=0; i<n; i++) scanf("%d", &num[i]);
for(int i=0; i<n; i++)
{
if(num[i] % 4 == 3) num[i]++;
else if(num[i] % 4 == 0 && num[i]) num[i]--;
}
int ans = 0;
for(int i=0; i<n; i++)
ans ^= num[i];
printf("%s\n", ans ? "Alice" : "Bob");
}
return 0;
}
暴力打表
#include <iostream>
using namespace std;
const int maxn = 1010;
int sg[maxn], vis[maxn], f[maxn];
void get_sg(int n)
{
for(int i=1; i<=n; i++)
{
for(int j=0; j<=maxn; j++) vis[j] = 0;
for(int j=0; j<i; j++) vis[sg[j]] = 1;
for(int j=1; j<i; j++)
vis[sg[j] ^ sg[i-j]] = 1;
for(int j=0; j<maxn; j++)
{
if(vis[j] == 0)
{
sg[i] = j;
break;
}
}
}
}
int main()
{
int n;
cin >> n;
get_sg(n);
for(int i=0; i<=n; i++)
{
cout << i << " : " << sg[i] << endl;
}
return 0;
}