UVA1566 John 题解

Description

\(n\) 堆糖果,每堆糖果有 \(a_i\) 颗。两个人轮流取糖果,每次取糖果可以在任意一堆里选任意多颗,可以把那一堆全部取完,但不能不取。取到最后一颗糖果的人算输。问先手必胜还是必败。

Solution

对于这类博弈论的问题,一种很常见的做法是:从最简单的情况开始考虑,逐步推广到更复杂的情况,再通过归纳得到所有情况的解。

首先要知道的是,在双方都采取最佳策略的情况下,不存在平局,只有先手必胜和先手必败的两种情况。接下来我们分情况讨论一下。

Case1:如果只有一颗糖果,那么显然先手必败。

Case2:将 Case1 推广一下,如果有奇数堆糖果,每堆糖果都只有一个,那么先手必胜。若是偶数堆则先手必败。

Case3:如果糖果数量不为 \(1\),怎么办?还是从最简单的情况开始考虑。假设糖果数量大于 \(1\) 的只有一堆,那么先手必胜。原因很简单,如果糖果数量为 \(1\) 的堆有奇数个,那么将最多的那一堆取完,否则将最多的那一堆取到只剩一个糖果即可,这样始终能让后手面临必败的局面。

Case4:如果至少有两堆糖果数量大于 \(1\),又该如何应对?这时可能的情况有太多种,不好从 Case3 推广。那么我们试着发掘一下 Case3 的性质。显然处于 Case3 时,每一堆糖果的个数的异或和一定大于 \(0\)。也就是说,如果每一堆糖果的个数的异或和等于 \(0\),那么在这样的状态下无论怎么取,都无法让对手面临必败态。这个时候对手根本输不了,只可能是自己输,先手必败。

那么如果异或和不等于 \(0\),是不是就先手必胜了呢?由于异或和为 \(0\) 时是必败态,因此我们只要想方设法让这一次取完后剩下的糖果的异或和为 \(0\) 就好了。

设当前有 \(n\) 堆糖果,每一堆糖果有 \(a_i\) 个,并且 \(x=a_1 \oplus a_2 \oplus a_3 \oplus\dots\oplus a_n\ne0\)。设 \(x\) 的二进制表示下最高位的 \(1\) 在第 \(k\) 位,那么至少存在一堆糖果 \(a_i\),它的第 \(k\) 位也是 \(1\)。显然 \(a_i \oplus x<a_i\),我们从 \(a_i\) 堆中取走若干颗糖果,使其变为 \(a_i \oplus x\),就得到了一个各堆糖果异或和等于 \(0\) 的局面。

也就是说,异或和不为 \(0\) 时,总是存在一种方案使得这一次取完后对手处于必败态。当对手处于必败态时,无论他怎么取,总是会回到异或和不为 \(0\) 的状态。由于糖果越取越少,先手一定能够到达 Case3 的局面。至此,我们已经成功证明了异或和不为 \(0\) 时是先手必胜。

代码实现时只需先判断是否满足 Case2,再判断异或和是否为 \(0\) 即可,非常简单。

Code

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int T;
	scanf("%d",&T);
	while(T--)
	{
		int n,x,ans=0,sum=0;
		scanf("%d",&n);
		for(int i=1;i<=n;i++) scanf("%d",&x),ans^=x,sum+=x;
		if(sum==n) (n&1)?puts("Brother"):puts("John");
		else ans?puts("John"):puts("Brother");
	}
	return 0;
}
posted @   __Star_Sky  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· 阿里巴巴 QwQ-32B真的超越了 DeepSeek R-1吗?
· 如何调用 DeepSeek 的自然语言处理 API 接口并集成到在线客服系统
· 【译】Visual Studio 中新的强大生产力特性
· 2025年我用 Compose 写了一个 Todo App
点击右上角即可分享
微信分享提示