http://acm.hdu.edu.cn/showproblem.php?pid=4388

Nim变形,对一个\(n\)个石子的堆,每次取\(k(0<k<n)\)个(注意不能全取光),同时要保证\(n\oplus k<n\),并添加一堆新的大小为\(n\oplus k\)的石子。

同时每个人在整个游戏中还有一次机会把添加的大小为\(n\oplus k\)的石子改为\(n\oplus (2k)\)个石子,同样是不能操作的输,两个人采取最优策略。

初步想法

一般性地,我们还是先不管\(n\oplus k\)变成\(n\oplus(2k)\)这个操作,先想清楚没有这种操作的情况

很自然地去手算几个小数据,以及往二进制的方向想(毕竟异或都出来了),\(n=1,2\)都直接不能操作,\(n=3=(11)_2\)的时候可以取一个\(k=1\)或者\(k=2\),接下来\(k=4=(100)_2\)又不能操作了…

仔细想想就会发现对于一个\(2^k=(\underbrace{100\dots00}_{k个0})_2\)不管怎么取一个比\(n\)小的\(k\),异或之后一定比\(n\)大,所以对于一堆的\(2^k\)就是一个不能操作的状态。同样如果是\((100\dots 010\dots 00)_2\)这样的东西,只要取一个\(k=(100\dots000\dots00),n\oplus k=(000\dots010\dots00)_2\)一定是满足条件的。

(也就是从\(n\)的1里面选一些1出来当\(k\),剩下\(n\oplus k\)一定是小于\(n\)的)

于是有了初步的想法,二进制表示下\(m\)个1的\(n\)至少可以按照这种拆法拆\(m-1\)次

进一步如果这么拆,当\(m\)是奇数时先手必败,否则必胜

进一步

不过仔细想想好像也不一定要那么拆,比如:

\[\begin{aligned}n=&(1101011)_2 \\k=&(0100100)_2\\n\oplus k=&(1001111)_2\end{aligned}
\]

5位→2位+5位,4次→1次+4次=5次,嗯?乍一看好像上面那样优雅的结论被破坏掉了…(当时推到这里差点放弃前面的思路…)冷静想一想,一次操作改变奇偶性…这不还是很河里嘛…(先手奇→留给后手偶)

而且虽然1的个数变多了,但是其实在两个人都采取最优策略的情况下具有必胜策略的那个人其实每次单独拿一个\(2^k\)出来就总是能把1的个数降下来…所以终究是能把游戏结束掉

证明一下?

似乎不管怎么拆,每次拆完都会改变奇偶性。怎么证呢…

  • 考虑某一位\(p\),如果\(n\)的这一位为1,\(p\)的为0,那么\(n\oplus k\)的结果是1
  • 类似地,列出四种情况,奇偶性一定不变

为什么呢…好像很显然…因为异或本来就是模二意义下的加法…奇偶性当然不变了…

证明了个寂寞

于是有结论:\(n\)中1的个数和\(k\)与\(n\oplus k\)中1的个数之和的奇偶性相同

好像快做完了

这么看来好像\(n\oplus k\to n\oplus (2k)\)就是纯粹拿来唬人的呀…毕竟奇偶性还是不变(因为\(k\)和\(2k\)中的1的个数是一样的,再套用上面的结论)

于是就愉快地做完了

根据初始状态算出来“能进行操作的次数”,判一下奇偶性

#include<bits/stdc++.h>
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
const int N=1e5+5;
int f[N];
inline int calc(int x)
{
if(f[x])return f[x];
int r=0;
while(x){if(x&1)r++;x>>=1;}
return f[x]=r;
}
int main()
{
int T;scanf("%d",&T);
rep(tc,1,T)
{
int n,r=0;
scanf("%d",&n);
rep(i,1,n)
{
int a;scanf("%d",&a);
r+=calc(a)-1;
}
printf("Case %d: ",tc);
if(r&1)printf("Yes\n");
else printf("No\n");
}
}

最新文章

  1. etl结合java的例子
  2. cmd输出的日志里有中文乱码的解决办法
  3. Androidmanifest之manifest标签详细介绍
  4. Qt Creator提示&quot;Qt没有被正确安装,请运行make install&quot;的解决办法
  5. Hadoop第9周练习—Hive部署测试(含MySql部署)
  6. Codeforces 746D:Green and Black Tea(乱搞)
  7. ztree check
  8. Apache Thrift - 可伸缩的跨语言服务开发框架
  9. ax 的错误处理范例
  10. 使用struts2实现文件上传
  11. 汇编Ring 3下实现 HOOK API
  12. Redis 配置文件 Redis.conf 参数说明
  13. jsp获得本地及serverIP的方法
  14. C#如何设置session过期时间
  15. 讲讲Linq to SQL映射(基础篇)
  16. c#类,接口,结构,抽象类介绍 以及抽象和接口的比较
  17. 201521123001 《Java程序设计》第14周学习总结
  18. 八、 Spring Boot 过滤器、监听器
  19. 海量数据挖掘MMDS week2: 频繁项集挖掘 Apriori算法的改进:基于hash的方法
  20. Spring Boot集成MyBatis的2种方式

热门文章

  1. YARN-MapReduce的作业提交流程
  2. 详细了解IDM的队列功能
  3. vue springboot利用easypoi实现简单导出
  4. P6823 「EZEC-4」zrmpaul Loves Array
  5. Qt5字符串编码转换学习
  6. VUE:组件总结
  7. How tomcat works(深入剖析tomcat)servlet容器
  8. 07_ListView
  9. 「考试」noip模拟9,11,13
  10. JZOJ8月10日提高组T2 Fix