【BZOJ:1299 [LLH邀请赛]巧克力棒 】题解
题目链接
题目
TBL和X用巧克力棒玩游戏。每次一人可以从盒子里取出若干条巧克力棒,或是将一根取出的巧克力棒吃掉正整数长度。TBL先手两人轮流,无法操作的人输。 他们以最佳策略一共进行了10轮(每次一盒)。你能预测胜负吗?
思路
以下写作中,“石子”与“巧克力”的意思相同。
先考虑一种特殊情况。
假设此时巧克力全部取出来,则这就是一个Nim游戏。
按照Nim游戏的做法,如果此时石子异或和为0,先手必败。
那如何使巧克力全取出来时异或和不为0呢?
-
假设所有巧克力异或和就0,那先手先把所有巧克力取出来,然后此时后手要面对全部取出来的异或和为0的石子,后手必败。
-
现在考虑第二种情况,就是所有巧克力的异或和不为0。
先手的目标在于,每一次拿出来后拿出的巧克力的异或和皆为0,也就是每次后手拿出的巧克力数的异或和不为0。
让我们考虑后手能进行的操作。
如果后手正常吃巧克力,先手直接用Nim游戏的方式即可。
那如果后手再拿出新的巧克力呢?
要使后手拿出巧克力的异或和不为0,就要满足可以拿出的巧克力的异或和不存在某些数异或和为0。
而要实现这一个目标,先手第一轮就必须把所有异或和为0的数全部拿出来,使得剩下的巧克力不存在任意多条异或和为0。
我们来验证一下此时行不行:
-
后手正常吃巧克力,就是一个Nim游戏。
-
后手拿出巧克力,而此时后手拿出巧克力的异或和必然不为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。
博弈论的题目主要有两种解题思路:
-
如此题,按Nim游戏的思想分类讨论
-
DP枚举所有情况
本文来自博客园,作者:zhangtingxi,转载请注明原文链接:https://www.cnblogs.com/zhangtingxi/p/16018140.html