Nim游戏 HDU1846
若各堆石子异或和为不为零,则先手胜 ,后手当且仅当异或和为零时取胜
此题问要想先手取胜第一步的取法,考虑到上述引理,只需遍历一遍石子找到异或和的最高位匹配的个数。
int a[105]; int main() { int m; while (scanf("%d", &m),m) { int cnt = 0; for (int i = 0; i < m; i++) scanf("%d", &a[i]); int nim = a[0]; for (int i = 1; i < m; i++) nim ^= a[i]; if (nim == 0) printf("0\n"); else { int tmp = 0; while (nim) nim /= 2, tmp++; tmp--; for (int i = 0; i < m; i++) if (a[i] & (1 << tmp)) cnt++; printf("%d\n", cnt); } } return 0; }
HDU 1848
在上题的基础上取法只许取斐波那契数列的大小
考虑SG函数模板
int f[50], sg[1005], mex[1005]; int getSG(int n) { sg[0] = 0; for (int i = 1; i <= n; i++) { memset(mex, 0, sizeof mex); for (int j = 1; f[j] <= i; j++) { mex[sg[i - f[j]]] = 1; } for (int j = 0;; j++) if (!mex[j]) { sg[i] = j; break; } } return sg[n]; } int main() { int n, m, p; f[1] = 1, f[2] = 2; for (int i = 2; f[i] <= 1005; i++) { f[i+1] = f[i] + f[i - 1]; } while (scanf("%d%d%d", &n, &m, &p),n||m||p) { if (getSG(n) ^ getSG(m) ^ getSG(p)) printf("Fibo\n"); else printf("Nacci\n"); } return 0; }
HDU1907
反Nim游戏,最后一步取的人败
先手必胜的情况有两种,只要是这两种情况之一就为先手必胜,
一:各堆石子数目异或结果不为零,且至少有一堆石子数目大于1
二:各堆石子数目异或结果为零,且所有堆石子数目均为1;
int a[50]; int main() { int T; int n; int ans; scanf("%d", &T); while (T--) { int rich = 0; scanf("%d", &n); for (int i = 0; i < n; i++) { scanf("%d", &a[i]); if (a[i] > 1) rich++; if (!i) ans = a[i]; else ans ^= a[i]; } if (ans == 0 && rich == 0) printf("John\n"); else if (ans && rich) printf("John\n"); else printf("Brother\n"); } }