题目链接
题意
黑板上有 n(n≤50)个不超过1 000 的正整数,Alice 和Bob 两人轮流操作,Alice 先操作。每次操作可以把一个数减1,或者擦掉两个数,然后写上它们的和。当一个数变成0时,会被自动擦掉,不能操作者输。如果双方均采用最优策略,谁会赢?
分析
非常好的一道纯逻辑推理游戏题,《算法竞赛入门经典--训练指南》还指出可以用动态规划求解。
如果n=1,唯一的这个数是奇数时Alice胜/偶数时Bob胜。
两个数呢?有1时必然Alice胜(最优策略:当另一个数为奇数时擦掉两数写上他们的和,否则擦掉1);没有1时,两数的Nim和为偶数时Alice胜/奇数时Bob胜(最优策略分析起来复杂一点,但也能想到)。
三个数呢?可先分析没有1时:三数的Nim和为奇数时Alice胜/偶数时Bob胜。仅一个1时:Alice必胜(三数的Nim和为偶数时擦掉1,否则擦掉1和另外任意一数的写上它两的和)。两个1时,结论和没有1时一样。
至此,就有点感觉了,首先要对1的数量奇偶性分类讨论,其次要对非1的数量也要分类讨论。为什么对非1的数量也要分类讨论?因为要考虑除了1之外仅有一个2的情况。
综上所述:
-
当非1的数量多于1时:有奇数个1则Alice必胜;有偶数个1则Nim和与n的奇欧性相同时Alice胜,奇欧性不同时Bob胜。
-
当非1的数量为0时(即全都是1):n不能被3整除则Alice胜,否则Bob胜。
-
当非1的数量为1时,要考虑1的数量(记为c)的奇偶性以及非1的那个数是否为2
-
奇数个1(c为奇数)时:
-
非1的那个数大于2则Alice必胜
-
非1的那个数等于2,c不能被3整除则Alice胜,否则Bob胜
-
偶数个1(c为偶数)时:
-
c不能被3整除,非1的那个数等于2则Alice胜,否则Bob胜
-
c能被3整除,非1的那个数是奇数则Alice胜,否则Bob胜
AC代码
#include <iostream>
using namespace std;
bool solve() {
int n, a, c = 0, s = 0, x = 0; cin >> n;
for (int i=0; i<n; ++i) {
cin >> a; s ^= a;
a == 1 ? ++c : x = a;
}
if (n-c > 1) return c&1 || (s&1)==(n&1);
if (n == c) return c%3;
if (c & 1) return c%3 || x>2;
return (c%3 && x==2) || x&1;
}
int main() {
ios::sync_with_stdio(false);
int t; cin >> t;
for (int kase=1; kase<=t; ++kase) cout << "Case #" << kase << ": " << (solve() ? "Alice" : "Bob") << endl;
return 0;
}