方法:博弈+构造
解析:
神题没想到咋做,看完wyf大爷说的话才懂
这道题的题意就是有n堆石子,之后你每次操作有两种做法
第一种是在已经建立的nim游戏上进行nim游戏。
第二种是在未被选的堆中选取若干堆加入这个nim游戏中。
所以这怎么做?
我一直尝试去建立一个必败态,不过可能我走的方法过多的考虑了将这道题转变为nim游戏套nim游戏而最终走入死胡同,不会做了。
然而这道题的必败态可以这么建:如果是先手的话,我可以建立出来一个异或和为0的nim游戏,此时后者有两种做法,第一种是在该nim游戏上游戏,则先手又可以将这个游戏的异或和变为0,第二种是选取新的石子堆加入原来的nim游戏,如果是先手的话不会给后手机会来添加一组异或和为0的石子堆。所以先手建立的一定是选取最多的元素的异或和为0的nim游戏,此时,在剩下的堆里,一定不能有一组石子堆的异或和为0,这很显然。
所以如果后者选取第二种做法,那么会使得原有的Nim游戏的异或和不为0,所以先手又可以将这个游戏的异或和变为0。
即如果先手开始选取最多石子堆来建立一个异或和为0的nim游戏,则后者必败。
又可以转化一下,如果先手可以选出一个任意数量的石子堆建立的异或和为0的nim游戏,则后者必败。
这很显然。
这道题石子堆的范围是14,所以我们可以
214
直接dfs淦。
或者高斯消元。
不过显然前者啊2333
代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 15
using namespace std;
int n;
int a[N];
bool v[N];
int flag;
void dfs(int no)
{
if(no==n+1)
{
int ans=0,cnt=0;
for(int i=1;i<=n;i++)if(v[i])ans^=a[i],cnt++;
if(!ans&&cnt!=0)
{
flag=1;
}
return;
}
v[no]=1;dfs(no+1);
v[no]=0;dfs(no+1);
}
int main()
{
int tot=10;
while(tot--)
{
scanf("%d",&n);
for(int i=1;i<=n;i++)scanf("%d",&a[i]);
memset(v,0,sizeof(v));
flag=0;
dfs(1);
if(flag)puts("NO");
else puts("YES");
}
}