题解取火柴游戏
Posted h-lka
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了题解取火柴游戏相关的知识,希望对你有一定的参考价值。
( ext{Solution:})
回顾一下(Nim)游戏那个优美结论的( ext{conclusion:})
将所有石子数量异或起来,若和为(0)则必败,否则必胜。(先手)
那分以下情况考虑:
首先是全(0:)此时必败,显然异或和为(0).
然后是异或和不为(0)的状态:那我们必定可以找到一个(a_i),将它改变,使得异或和为(0).
因为二进制异或下的某一位是(1)的话则一定有奇数个数在此处是(1).那么我们随意找一个,令异或和为(k).将(a_i o a_i ext{^} k)则这个数必然比原来的(a_i)小。因为最高位改变了。
第三种情况是异或和为(0)时不存在一种移动使得下一步的异或和依旧是(0).
因为如果让(a_i o a_i*)成立的话,则必然有(a_i*=a_i),是一个不合条件的移动。
那么对于这个题:第一步用(Nim)和判断是不是必败,第二步枚举每一个队看看能不能修改即可。
#include<bits/stdc++.h>
using namespace std;
int n,a[5000010],s;
pair<int,int>p;
int main(){
scanf("%d",&n);
for(int i=1;i<=n;++i)scanf("%d",a+i);
for(int i=1;i<=n;++i)s^=a[i];
if(s==0){
puts("lose");
return 0;
}
for(int i=1;i<=n;++i){
int S=s;
S^=a[i];
if(a[i]>=S){
p.first=a[i]-S;
p.second=i;
a[i]-=p.first;
break;
}
}
printf("%d %d
",p.first,p.second);
for(int i=1;i<=n;++i)printf("%d ",a[i]);
puts("");
return 0;
}
以上是关于题解取火柴游戏的主要内容,如果未能解决你的问题,请参考以下文章
ybtoj 博弈论课堂过关luogu P1247luogu P2197模板nim 游戏 & 取火柴游戏 &例题1取火柴游戏