思维型博弈。
题意:Alice和Bob互相取石子,每次选择恰好
n
/
2
n/2
n/2堆,从每一堆里取至少一个,第一个不能完成取的算为输。
思路:构造一种能够把对方气死的方案。
我们先考虑这些情况:
1 1 1 1 1 1时一定是后手必胜。(显然)
1 1 1 1 1 2 时也是后手必胜。(也是显然)
但1 1 1 2 2 2 就成了先手必胜,因为可以一次取到1 1 1 1 1 1的情况。
然后1 1 2 2 2 2也是先手必胜。
2 2 2 2 2 2是后手必胜。
我们可以得到n = 6时的如下表:
石子 | 胜负 |
---|---|
1 1 1 1 1 1 | 后手 |
1 1 1 1 1 2 | 后手 |
1 1 1 1 2 2 | 后手 |
1 1 1 2 2 2 | 先手 |
1 1 2 2 2 2 | 先手 |
1 2 2 2 2 2 | 先手 |
2 2 2 2 2 2 | 后手 |
2 2 2 2 2 3 | 后手 |
2 2 2 2 3 3 | 后手 |
2 2 2 3 3 3 | 先手 |
我们可以猜想,当最小的数字出现的次数大于
n
/
2
n/2
n/2的时候,后手一定必胜。因为我们可以构造如下方案:
不妨令当前最小值为d。A一定会在一次取完之后,其中至少一堆的最小值小于d,假设为
d
′
d'
d′。然后B一定存在一种方案,让所有堆中石子数等于
d
′
d'
d′的堆的个数超过
n
/
2
n/2
n/2,这样先手面临的情况与之前相同,推到最后,后手一定可以取出超过
n
/
2
n/2
n/2个0。这样先手必败。
所以,只需判断当前情况的最小值个数与
n
/
2
n/2
n/2间的关系即可。
代码:
#include <bits/stdc++.h>
#define __ ios::sync_with_stdio(0);cin.tie(0);cout.tie(0)
#define ll long long
using namespace std;
const int maxn = 1e5 + 10;
int n, a[maxn];
int main() {
cin >> n;
int minm = 1e8;
for (int i = 1; i <= n; ++i) {
cin >> a[i];
minm = min(minm, a[i]);
}
int cnt = 0;
for (int i = 1; i <= n; ++i) {
if (a[i] == minm)cnt++;
}
if (cnt + cnt > n) {
cout << "Bob" << endl;
}
else cout << "Alice" << endl;
return 0;
}