首先我们看例题:P2197 nim游戏

题目描述

甲,乙两个人玩Nim取石子游戏。

nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取。每次只能从一堆里取。最后没石子可取的人就输了。假如甲是先手,且告诉你这n堆石子的数量,他想知道是否存在先手必胜的策略。

输入输出格式

输入格式:

第一行一个整数T<=10,表示有T组数据

接下来每两行是一组数据,第一行一个整数n,表示有n堆石子,n<=10000;

第二行有n个数,表示每一堆石子的数量

输出格式:

共T行,如果对于这组数据存在先手必胜策略则输出"Yes",否则输出"No",不包含引号,每个单词一行。

输入输出样例

输入样例#1:

2
2
1 1
2
1 0
输出样例#1:

No
Yes

讲解:
本题就是最最经典的nim游戏了。nim游戏过程中面临的状态叫做局面,第一个行动的为先手,第二个行动的为后手。考虑两人无比聪明,则必败局面仅当该局面所能到达的局面均为必败局面时出现,而必胜局面仅当后续局面存在至少1个必胜局面时出现,显然nim游戏中1为必胜局面(因为拿走1就赢了)。显然,nim游戏是不存在平局的,只有先手必赢或先手必输两种情况。

定理:设各堆为a1、a2…an,则nim游戏先手必赢仅当a1 Xor a2 Xor…Xor an≠0.

证明:

  首先,当石子均被取完时,则a数组都为0,存在a1 Xor a2 Xor…Xor an=0,因为每次取都会使石子数减少,当前局面若a1 Xor a2 Xor…Xor an≠0,我们只要保证能在取走一些石子后使得a1 Xor a2 Xor…Xor an=0,则必然保证自己能取走最后一个石子获得胜利。

  等价于证明:

  (1)当a1 Xor a2 Xor…Xor an≠0时,存在某种取法使得剩下的石子xor和为0。

  (2)当a1 Xor a2 Xor…Xor an=0时,不存在取法使得剩下的石子xor和为0。(即取走一些石子后必定Xor和不为0)

  首先证明(1),对于任何一个局面a1 Xor a2 Xor…Xor an=x≠0,设x的二进制最高位的1在第k位,则至少存在一堆石子ai的二进制第k位是1(因为我们是Xor运算,某一位上的1不会凭空出现)且ai≥x。由Xor运算法则知:x Xor ai<ai,(因为至少会使第k为上的1变为0)。于是我们从ai这堆里取走一些石子,使得ai堆剩下的石子数变为ai Xor x,此时再对剩下的各堆进行上述运算:a1 Xor a2 Xor…ai Xor x…Xor an=x Xor x=0,此时Xor和为0。 于是得证(1)。

  再来证明(2),对于任何一个局面a1 Xor a2 Xor…Xor ai Xor…an=0,我们反证:假设取走ai堆中的一些石子使ai变为了x,使得a1 Xor a2 Xor…Xor x Xor…an≠0,则显然是不可能的,因为开始Xor和就为0再由Xor运算的性质当ai变为x后若Xor和为0,当且仅当ai=x时成立。而nim游戏中不能不取,所以若当前局面Xor和为0,则必然会使下一局面Xor和不为0。于是(2)得证。

结论:nim游戏只要满足先手的Xor和不为0,则先手必赢,否则先手必输。

代码:

#include<bits/stdc++.h>
#define il inline
#define ll long long
using namespace std;
il ll gi()
{
ll a=;char x=getchar();bool f=;
while((x<''||x>'')&&x!='-')x=getchar();
if(x=='-')x=getchar(),f=;
while(x>=''&&x<='')a=a*+x-,x=getchar();
return f?-a:a;
}
ll t,n,a[];
int main()
{
t=gi();
while(t--){
n=gi();ll x=;
for(int i=;i<=n;i++)a[i]=gi(),x^=a[i];
if(x)puts("Yes");
else puts("No");
}
return ;
}

浅析Nim游戏(洛谷P2197)的更多相关文章

  1. 洛谷 P2197 nim游戏

    洛谷 P2197 nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取 ...

  2. 洛谷 P2197 【模板】nim游戏 解题报告

    P2197 [模板]nim游戏 题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以 ...

  3. 洛谷P2197 nim游戏(Nim游戏)

    题目描述 甲,乙两个人玩Nim取石子游戏. nim游戏的规则是这样的:地上有n堆石子(每堆石子数量小于10000),每人每次可从任意一堆石子里取出任意多枚石子扔掉,可以取完,不能不取.每次只能从一堆里 ...

  4. [洛谷P2197]nim游戏

    题目大意:Nim游戏.地上有n堆石子,每人每次可从任意一堆石子里取出任意多石子,不能不取,且每次只能从一堆里取.没石子可取的人输.问是否存在先手必胜的策略. 题解:Nim游戏有一个定理,就是当所有棋子 ...

  5. P4554 小明的游戏 (洛谷) 双端队列BFS

    最近没有更新博客,全是因为英语,英语太难了QWQ 洛谷春令营的作业我也不会(我是弱鸡),随机跳了2个题,难度不高,还是讲讲吧,学学新算法也好(可以拿来水博客) 第一题就是这个小明的游戏 小明最近喜欢玩 ...

  6. NOIP2012 Day1 T2国王游戏 洛谷P1080

    第一篇博客啊…… 由于我太弱了,还要去补不全的知识点准备参加人生第一次NOIp,所以第一篇博客就简短一点好了(偷懒就直说吧……) 洛谷P1080传送门 题意概括: 有N对数ai和bi,以及两个数a0和 ...

  7. 洛谷P2197 nim游戏模板

    Code: #include<iostream> using namespace std; int main(){ int t; cin>>t; while(t--){ int ...

  8. AC日记——欧几里得的游戏 洛谷 P1290

    题目描述 欧几里德的两个后代Stan和Ollie正在玩一种数字游戏,这个游戏是他们的祖先欧几里德发明的.给定两个正整数M和N,从Stan开始,从其中较大的一个数,减去较小的数的正整数倍,当然,得到的数 ...

  9. 矩阵取数游戏洛谷p1005

    题目描述 帅帅经常跟同学玩一个矩阵取数游戏:对于一个给定的n*m的矩阵,矩阵中的每个元素aij均为非负整数.游戏规则如下: 1.每次取数时须从每行各取走一个元素,共n个.m次后取完矩阵所有元素: 2. ...

随机推荐

  1. redis外部访问

    1.redis的搭建这里就不做描述的了,可以参考我的另外一个博客. http://www.cnblogs.com/ll409546297/p/6993778.html 2.说明一下我们在其他服务器上面 ...

  2. JMeter常用元器件

    测试计划, 是整个工程的根节点, 可以取别名, 并添加注释, 里面的设置是全局变量: 线程组, 是一组线程的集合, 可以取别名, 并添加注释, 里面的设置只对本线程组有效: HTTP请求, 也就是取样 ...

  3. Linux命令应用大词典-第31章 设备管理

    31.1 udevadm info:查询udev数据库中的设备信息 31.2 mkdnod:创建块设备和字符设备文件 31.3 MAKEDEV:创建/dev中的设备 31.4 lsblk:列出块设备信 ...

  4. Java Swing学习笔记——创建JFrame

    创建显示一个空JFrame import javax.swing.JFrame; public class JFrameDemo extends JFrame{ public JFrameDemo() ...

  5. 【WXS数据类型】Array

    属性: 名称 值类型 说明 [Array].constructor [String] 返回值为“Array”,表示类型的结构字符串 [Array].length [Number] 返回数组长度 方法: ...

  6. XX出行项目子系统-统计系统设计(定时器项目设计例子)

    一. 引言 目前开发的XX出行系统,需要开发数据统计功能,鉴于约约出行系统已经在运营,并且有新版本的迭代,方便以后下个版本复用,遂新建一个子系统. 二. 架构设计 三. 具体实现 1.MySql数据库 ...

  7. SpringCloud IDEA 教学 番外篇 后台运行Eureka服务注册中心

    写在开头 研发过程中经常要做的事就是启动Eureka服务注册中心,每每都要启动一个IDEA,很是困扰.现在分享一个后台启动服务注册中心的方法. 准备工作 1打包一个eureka服务注册中心jar包(注 ...

  8. UVA 11922 Permutation Transformer(平衡二叉树)

    Description Write a program to transform the permutation 1, 2, 3,..., n according to m instructions. ...

  9. 浮点数(floating-point number)二进制存储格式

    定义 浮点数就是小数点位置不固定的数,也就是说与定点数不一样,浮点数的小数点后的小数位数可以是任意的,根据IEEE754-1985(也叫IEEE Standard for Binary Floatin ...

  10. C++纯虚函数、虚函数、实函数、抽象类,重载、重写、重定义

    首先,面向对象程序设计(object-oriented programming)的核心思想是数据抽象.继承.动态绑定.通过数据抽象,可以使类的接口与实现分离,使用继承,可以更容易地定义与其他类相似但不 ...