百度百科

Definition

这样的游戏被称为Nim游戏:

1、有两个玩家,轮流进行操作

2、是公平游戏。即面对同一局面两个玩家所能进行的操作是相同的。例如中国象棋不是公平游戏。因为面对同一个局面,红方只能移动红色棋子而不能移动黑方棋子,黑房同理。

3、一个玩家是输掉当且仅当他无法进行操作。例如如果是两个人轮流取石子的游戏,那么一个玩家输掉当且仅当他面前没有石子了。因为他下面无法进行取石子的操作。

一般的,Nim游戏指两个玩家轮流在好几堆东西中取物品,不能夸堆取,无法操作判负。

Solution

对于Nim游戏的解法,因为状态显然是不可逆的,所以可以对状态的转移图进行拓扑排序然后DP求解。但是对于大部分博弈题目,状态多的难以计算,所以需要考虑更简单的方法。

结论:一个Nim游戏中的状态是必败状态当且仅当每个子游戏的异或和为0.

这里子游戏代表构成Nim游戏中最基础的游戏。例如两个人轮流取三堆石子的游戏是三个取一堆石子的游戏组合而成的。对于每个子游戏显然可以用一个正整数代表当前的状态,即还剩多少石子。Nim游戏的子游戏状态异或和为\(0\),则必败。

证明:我有一个绝妙的想法,可惜这里写不开

对于一个异或和不为\(0\)的状态,那么他是必胜态。

考虑在一个必胜态下如何进行下一步。

设异或和是\(X\)。设\(X\)二进制的最高为1位是第\(k\)位。

那么显然存在至少一个状态使得他们二进制第\(k\)位为1。否则第k位异或和应该是0。

那么就任选一个第k位是1的状态,设他的状态是\(Y\),那么将他可以将\(Y\)这一堆取成\(Z=X~xor~Y\)那么得到的状态是必败状态。

证明如下:

首先,\(Y\)可以取成\(Z\)当且仅当\(Z~\leq~Y\)。首先证明\(Z~\leq~Y\)。

因为\(Y\)和\(X\)第\(k\)位都是\(1\),更高位都是\(0\)。那么异或后\(Z\)第\(k\)位一定是\(0\),更高位显然是\(0\)。所以\(Z\)的位数比\(Y\)的位数要少。那么显然\(Z~\leq~Y\)。

下面证明更改后的状态是必败状态

根据\(Z=X~xor~Y\),并且\(A~xor~A=~0~\)。可得:

更改后的状态

\(S~=~X~xor~Y~xor~Z~=~X~xor~Y~xor~(~X~xor~Y~)\)

\(=~(~X~xor~Y~)~xor~(~X~xor~Y~)~=~0~\)

一定是一个必败状态。

Example

传送门

Description

输入k及k个整数n1,n2,…,nk,表示有k堆火柴棒,第i堆火柴棒的根数为ni;接着便是你和计算机取火柴棒的对弈游戏。取的规则如下:每次可以从一堆中取走若干根火柴,也可以一堆全部取走,但不允许跨堆取,也不允许不取。

Input

第一行,一个正整数k

第二行,k个整数n1,n2,…,nk

Output

如果是先取必胜,请在第一行输出两个整数a,b,表示第一次从第b堆取出a个。第二行为第一次取火柴后的状态。如果有多种答案,则输出<b,a>字典序最小的答案(即b最小的前提下a最小)。

如果是先取必败,则输出“lose”。

Sample Input_1

3
3 6 9

Sample Output_1

4 3
3 6 5

Sample Input_2

4
15 22 19 10

Sample Output_2

lose

Hint

\(k~\leq~500000\)

\(n_i~\leq~1e9\)

Solution

板子题要啥solution

Code

#define rg register
#define ci const int
#define cl const long long int typedef long long int ll; namespace IO {
char buf[90];
} template<typename T>
inline void qr(T &x) {
char ch=getchar(),lst=' ';
while(ch>'9'||ch<'0') lst=ch,ch=getchar();
while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
if(lst=='-') x=-x;
} template<typename T>
inline void write(T x,const char aft,const bool pt) {
if(x<0) x=-x,putchar('-');
int top=0;
do {
IO::buf[++top]=x%10+'0';
x/=10;
} while(x);
while(top) putchar(IO::buf[top--]);
if(pt) putchar(aft);
} template<typename T>
inline T mmax(const T a,const T b) {if(a>b) return a;return b;}
template<typename T>
inline T mmin(const T a,const T b) {if(a<b) return a;return b;}
template<typename T>
inline T mabs(const T a) {if(a<0) return -a;return a;} template<typename T>
inline void mswap(T &a,T &b) {
T temp=a;a=b;b=temp;
} const int maxn = 500010; int n,ans;
int MU[maxn]; int main() {
qr(n);
for(rg int i=1;i<=n;++i) {
qr(MU[i]);ans^=MU[i];
}
if(!ans) {
puts("lose");return 0;
}
int _temp=1<<30;
while(!( _temp & ans )) _temp>>=1;
for(rg int i=1;i<=n;++i) if(MU[i] & _temp){
int z=ans^MU[i];
write(MU[i]-z,' ',true);write(i,'\n',true);
for(rg int j=1;j<=n;++j) {
if(j != i) write(MU[j],' ',true);
else write(z,' ',true);
}
break;
}
return 0;
}

Summary

Nim游戏是必败态当且仅当子游戏状态异或和为0。否则是必胜态。通过必胜态一定可以通过一步操作变成必败状态。

最新文章

  1. C# 泛型
  2. HYSBZ 2002 分块
  3. MicroERP软件更新记录1.1
  4. Cosh.3
  5. themeforest 模板
  6. stack计算表达式的值
  7. phpMyAdmin import.php 安全漏洞
  8. java 操作POI参考文章
  9. 常用两种数据交换格式之XML和JSON的比较
  10. 王立平--Unity中间GUI Skin
  11. C语言ftell()函数
  12. 1、在Centos上安装Grafana
  13. 深度学习(pytorch)-1.基于简单神经网络的图片自动分类
  14. Mysql 锁和锁算法
  15. 使用8.0版本jdbc驱动连接数据库操作
  16. ftrace利器之trace-cmd和kernelshark
  17. 跨域(五)——postMessage
  18. Linux设备驱动剖析之SPI(一)
  19. NULLIF与ISNULL的交叉使用
  20. C++与Java混合编程

热门文章

  1. 6.2 element和elements
  2. Java开发工程师(Web方向) - 02.Servlet技术 - 第2章.Cookie与Session
  3. 完全背包问题 :背包dp
  4. 前端整合MathjaxJS的配置笔记
  5. dice2win早期版本
  6. nodejs基础学习
  7. JavaScript初探系列之日期对象
  8. UVALive - 6869 Repeated Substrings 后缀数组
  9. hashMap原理(java8)
  10. Java核心技术点之接口