【BZOJ:1299 [LLH邀请赛]巧克力棒 】题解

题目链接

题目

TBL和X用巧克力棒玩游戏。每次一人可以从盒子里取出若干条巧克力棒,或是将一根取出的巧克力棒吃掉正整数长度。TBL先手两人轮流,无法操作的人输。 他们以最佳策略一共进行了10轮(每次一盒)。你能预测胜负吗?

思路

以下写作中,“石子”与“巧克力”的意思相同。

先考虑一种特殊情况。

假设此时巧克力全部取出来,则这就是一个Nim游戏。

按照Nim游戏的做法,如果此时石子异或和为0,先手必败。

那如何使巧克力全取出来时异或和不为0呢?

  1. 假设所有巧克力异或和就0,那先手先把所有巧克力取出来,然后此时后手要面对全部取出来的异或和为0的石子,后手必败。

  2. 现在考虑第二种情况,就是所有巧克力的异或和不为0。

先手的目标在于,每一次拿出来后拿出的巧克力的异或和皆为0,也就是每次后手拿出的巧克力数的异或和不为0。

让我们考虑后手能进行的操作。

如果后手正常吃巧克力,先手直接用Nim游戏的方式即可。

那如果后手再拿出新的巧克力呢?

要使后手拿出巧克力的异或和不为0,就要满足可以拿出的巧克力的异或和不存在某些数异或和为0。

而要实现这一个目标,先手第一轮就必须把所有异或和为0的数全部拿出来,使得剩下的巧克力不存在任意多条异或和为0。

我们来验证一下此时行不行:

  1. 后手正常吃巧克力,就是一个Nim游戏。

  2. 后手拿出巧克力,而此时后手拿出巧克力的异或和必然不为0,所以所有拿出的异或和必然不为0,先手照样用Nim游戏的方式使异或和为0。

通过这样,我们成功验证了我们刚才的猜想。

那什么时候先手必败呢?

如果在原先的巧克力里不存在任意几根异或和为0,则先手必败。

让我们来验证一下,此时由于拿出来的巧克力异或和不为0,后手按Nim游戏的方法取为0,然后就转化为刚刚的情况,先手必败。

时间复杂度 \(O(2^n)\),主要在于暴力枚举子集判断是否存在异或和为0的子序列。

Code

#include<bits/stdc++.h>
using namespace std;
//#define int long long
inline int read(){int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;
ch=getchar();}while(ch>='0'&&ch<='9'){x=(x<<1)+
(x<<3)+(ch^48);ch=getchar();}return x*f;}
#define N 50
//#define M
//#define mo
int n, m, i, j, k, T, flg; 
int a[N]; 

void dfs(int k, int s)
{
	if(k>n) 
	{
		if(!s) ++flg;  
	}
	else
	{
		dfs(k+1, s); 
		dfs(k+1, s^a[k]); 	
	}
	
}

signed main()
{
//	freopen("tiaoshi.in","r",stdin);
//	freopen("tiaoshi.out","w",stdout);
	T=10; 
	while(T--)
	{
		n=read(); m=0; 
		for(i=1; i<=n; ++i) a[i]=read(), m^=a[i] ; 
		if(!m) printf("NO\n"); 
		else
		{
			flg=0; dfs(1, 0); 
			printf(flg>1 ? "NO\n" : "YES\n"); 
		}	
	}
	return 0;
}

总结

这题是一条博弈论题目的综合运用,有点难度。

这题最重要的是抓住Nim游戏的关键性质:异或和是否为0。

然后分别讨论各种情况如何使异或和为0。

博弈论的题目主要有两种解题思路:

  1. 如此题,按Nim游戏的思想分类讨论

  2. DP枚举所有情况

posted @ 2022-03-17 17:19  zhangtingxi  阅读(133)  评论(0编辑  收藏  举报