题目大意
给定一个 n n n个数的集合,Alice和Bob轮流操作,Alice先操作,每次选最大的数,将其减少任意值,再放回集合(需一直满足集合中元素互不相同的规定),集合中的数 a i ≥ 0 a_i \ge 0 ai≥0。谁先不能操作,谁就会输掉游戏输掉。
给定 n , a i n, a_i n,ai,问谁会获胜。
思路
这是一道相当妙的博弈论,这个游戏是个 I C G ICG ICG,也就是说,存在必胜策略。我们把数都从小到大排序(每次执行操作后也排序)。
我们假设:
- 先手把 a n a_n an减少到比 a n − 1 a_{n-1} an−1小,是必胜策略,那么我们就直接这么做
- 如果先手把 a n a_n an减少到比 a n − 1 a_{n-1} an−1小不是必胜策略(也就是必败策略),且假设 a n > a n − 1 + 1 a_n > a_{n-1} + 1 an>an−1+1,那我们先手让 a n = a n − 1 + 1 a_n = a_{n-1} + 1 an=an−1+1,那么后手就只能把 a n a_n an减少到小于 a n − 1 a_{n-1} an−1,然而这是个必败策略,也就是说,可以把必败情况给后手,即也是先手必胜。
那么假如 a n = a n − 1 + 1 a_n = a_{n-1} + 1 an=an−1+1,那么双方的策略就一直是维持 a n = a n − 1 a_n = a_{n-1} an=an−1,直到无法操作,因为一旦不满足这个条件,那么另外一方就能利用 a n > a n − 1 + 1 a_n > a_{n-1} + 1 an>an−1+1这个条件取胜。
那么一直这么做的话,执行最后一步的人会取胜,而执行到最后集合一定是 0 , 1 , 2 , . . . , n − 1 0,1,2,...,n-1 0,1,2,...,n−1。且我们发现操作次数其实就是 a n − ( n − 1 ) a_n - (n-1) an−(n−1),是的,很神奇和其它数无关,因为我们每次减少数,不能和其它数重合,且满足 a n = a n − 1 a_n = a_{n-1} an=an−1,也就是说 [ 0 , a n ] [0,a_n] [0,an]中每个数都会被遍历到,所以其它数在哪都没关系。
那么可执行次数为奇数,先手必胜,否则后手必胜。
代码
#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
const int maxN = 3e5 + 7;
int n, a[maxN];
int main()
{
scanf("%d", &n);
for(int i = 1; i <= n; ++i)
scanf("%d", &a[i]);
sort(a + 1, a + 1 + n);
if(a[n] - a[n - 1] > 1)
printf("Alice\n");
else {
if((a[n] - (n - 1)) % 2)
printf("Alice\n");
else
printf("Bob\n");
}
return 0;
}