博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
[CQOI2013]新Nim游戏
阅读量:6933 次
发布时间:2019-06-27

本文共 1227 字,大约阅读时间需要 4 分钟。

在Nim游戏中,限定第一回合玩家可以拿走任几堆石子,但不能全部拿完,同样第二回合选手进行同样操作,接下来的回合同Nim游戏操作,询问先手是否必胜所拿走的最少的石子。

不难得知应该要用Nim游戏的结论,自然想到暴力建SG函数,但是注意问题只有前两个回合特殊,根据Nim定理,换一种解释即选出最多的数构成一个集合,使其任意子集异或和不为0。

异或和问题,考虑线性基,现在我们有了如何判断异或和是否为0的工具,经验告诉我们自由选择一般不能递推,于是考虑贪心,从大到小选择,如果能够加入线性基,就选择即可,正确性证明如下。


证明:

假设选到第i个数\(a_i\),前i个数已经选到最优情况,如果不是最优的情况,必然至少存在\(a_j,a_k\)使其和大于\(a_i\),并且因为\(a_i\)的存在,不能加入线性基,但是\(a_i\)在线性基中只占一个二进制位,而因为其存在而不能选这两个数,意味着这两个数加入线性基时必然也占这一个二进制位,而位置只有一个,故显然它们会互斥,于是矛盾,得证。


参考代码:

#include 
#include
#include
#define il inline#define ri register#define ll long longusing namespace std;struct linear_base{ int base[32]; il bool insert(int x){ ri int i; for(i=31;i>=0;--i) if(x>>i){ if(base[i])x^=base[i]; else return base[i]=x; }return false; }}B;int a[101];il void read(int&);int main(){ int k,i;ll ans(0);read(k); for(i=1;i<=k;++i)read(a[i]);sort(a+1,a+k+1); for(i=k;i;--i)if(!B.insert(a[i]))ans+=a[i]; printf("%lld",ans); return 0;}il void read(int &x){ x&=0;ri char c;while(c=getchar(),c<'0'||c>'9'); while(c>='0'&&c<='9')x=(x<<1)+(x<<3)+(c^48),c=getchar();}

转载于:https://www.cnblogs.com/a1b3c7d9/p/10859551.html

你可能感兴趣的文章
Oracle开发常用函数与存储过程
查看>>
修改PHP上传文件大小限制的方法
查看>>
OLAP与OLTP介绍
查看>>
Mac 安装md5sum等
查看>>
memcached client --ref
查看>>
MyBatis魔法堂:ResultMap详解
查看>>
《基于Windows 7特性的程序开发系列》视频分享
查看>>
SilverLight.3-Validation:二、银光验证。TheLabel、TheDescriptionViewer和TheValidationSummary...
查看>>
二叉树的非递归遍历(递归和非递归)
查看>>
第 13 章 编码风格
查看>>
WPF 浏览PDF 文件
查看>>
代码的印象派:写点好代码吧
查看>>
javascript全局观
查看>>
1.4. Rosegarden
查看>>
查看oralce的版本及安装了哪些选项
查看>>
uC/OS-II源码分析(四)
查看>>
图像编程魔法门(By C#) 目录
查看>>
cross join
查看>>
jsoup 多个 class Selector 怎么写?
查看>>
让你上瘾的网易云音乐推荐算法,用Word2vec就可以实现
查看>>