一起养成写作习惯!这是我参与「掘金日新计划 · 4 月更文挑战」的第18天,点击查看活动详情。
题目描述
石子游戏 II - 题目 - Daimayuan Online Judge
Alice 和 Bob 正在玩一个关于石头的游戏。
共有 n 堆石头,其中第 i 堆最初含有 ai 个石子。
他们轮流执行下列操作之一,从 Alice 开始。
把一堆奇数的石头劈成两堆,两堆都不能空。
把两堆偶数的石头合成一堆。
不能执行任何操作的人将输掉游戏。
假设 Alice 和 Bob 都足够聪明,你知道谁会赢得游戏吗?
输入格式
第一行包含一个整数 n (1≤n≤106)
第二行包含 n 个正整数 a1,…,an (1≤a1,…,an≤109)
输出格式
Alice 或 Bob,表示最终赢家
样例输入
2
2 2
样例输出
Alice
问题解析
博弈论。
让我们来分情况讨论一下怎么样才能赢:
一、只剩下一堆石头,且这堆石头是偶数。
二、剩下的石头都是数量为1。
三、只有一个是偶数堆石头,其它都是数量为1。
那么也就是说,我们想赢,就是把所有的偶数都合起来,奇数都切成1。然后我们来看一下步骤:
如果有n个数量为偶数的石头,那我们将会进行n-1次操作才能把所有石头合成一堆。
如果是奇数的石头,我们可以先切一刀后把它变成一个1和一个偶数石头(不一定要对半分的啊),如果还有偶数石头,就可以把这个偶数石头和另一堆合起来。那么看起来我们要记录一下大于1的奇数石头和大于0的偶数石头的个数?
其实不用这么麻烦,你想:
如果只有一个奇数石头,那我们alice批完一刀后就变成一个1和一个偶数石头,bob就不能行动了。
如果只有两个奇数石头,那我们alic和bob各批完一刀后,变成了两个1石头和两个偶数石头,此时alice把这两个偶数石头合起来,bob又没事干了。
所以其实不管奇数石头的数量,最后都该是alice赢(除非奇数石头全是1,那么Alice就直接输了)。
所以我们就看偶数的情况就可以了,而偶数情况也很直观,那就是要进行(偶数石头数量-1)次操作,这样我们就很容易的计算出哪个角色是完成最后一次合成操作的人。
此时我们就可以得到结论了:
大于0的偶数石头数量为0时,只要奇数石头有大于1的,那就是alic赢
大于0的偶数石头数量不为0时,数量为偶数时Alice赢,反之bob赢
其它情况都是bob赢
#include<iostream>
using namespace std;
#include<vector>
#include<algorithm>
#include<math.h>
#include<set>
#include<numeric>
#include<string>
#include<string.h>
#include<iterator>
#include<map>
#include<unordered_map>
#include<stack>
#include<list>
#include<queue>
#include<iomanip>
#define endl '\n';
typedef long long ll;
typedef pair<int, int> PII;
inline int read() {
int x = 0; char ch = getchar();
while (ch < '0' || ch > '9') ch = getchar();
while (ch >= '0' && ch <= '9') x = (x << 3) + (x << 1) + ch - '0', ch = getchar();
return x;
}
int main()
{
cin.sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
int n = read();
int x, res = 0;
bool flag = false;
for (int i = 0; i < n; i++)
{
x = read();
if (x % 2 == 0)res++;
if (x != 1)flag = true;
}
if ((res != 0 && res % 2 == 0) || (res == 0 && flag))
{
cout << "Alice" << endl;
}
else cout << "Bob" << endl;
return 0;
}