当前位置: 首页 > news >正文

2024/5/28 P1247 取火柴游戏

取火柴游戏

题目描述

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

谁取走最后一根火柴为胜利者。

例如: k = 2 k=2 k=2 n 1 = n 2 = 2 n_1=n_2=2 n1=n2=2,A 代表你,P 代表计算机,若决定 A 先取:

  • A: ( 2 , 2 ) → ( 1 , 2 ) (2,2) \rightarrow (1,2) (2,2)(1,2),即从第一堆中取一根。
  • P: ( 1 , 2 ) → ( 1 , 1 ) (1,2) \rightarrow (1,1) (1,2)(1,1),即从第二堆中取一根。
  • A: ( 1 , 1 ) → ( 1 , 0 ) (1,1) \rightarrow (1,0) (1,1)(1,0)
  • P: ( 1 , 0 ) → ( 0 , 0 ) (1,0) \rightarrow (0,0) (1,0)(0,0)。P 胜利。

如果决定 A A A 后取:

  • P: ( 2 , 2 ) → ( 2 , 0 ) (2,2) \rightarrow (2,0) (2,2)(2,0)
  • A: ( 2 , 0 ) → ( 0 , 0 ) (2,0) \rightarrow (0,0) (2,0)(0,0)。A 胜利。

又如 k = 3 k=3 k=3 n 1 = 1 n_1=1 n1=1 n 2 = 2 n_2=2 n2=2 n 3 = 3 n_3=3 n3=3 A A A 决定后取:

  • P: ( 1 , 2 , 3 ) → ( 0 , 2 , 3 ) (1,2,3) \rightarrow (0,2,3) (1,2,3)(0,2,3)
  • A: ( 0 , 2 , 3 ) → ( 0 , 2 , 2 ) (0,2,3) \rightarrow (0,2,2) (0,2,3)(0,2,2)
  • A 已将游戏归结为 ( 2 , 2 ) (2,2) (2,2) 的情况,不管 P 如何取 A 都必胜。

编一个程序,在给出初始状态之后,判断是先取必胜还是先取必败,如果是先取必胜,请输出第一次该如何取。如果是先取必败,则输出 lose

输入格式

第一行,一个正整数 k k k

第二行, k k k 个整数 n 1 , n 2 , ⋯ , n k n_1,n_2,\cdots,n_k n1,n2,,nk

输出格式

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

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

样例 #1

样例输入 #1

3 3 6 9

样例输出 #1

4 3 3 6 5

样例 #2

样例输入 #2

4 15 22 19 10

样例输出 #2

lose

提示

数据范围及约定

对于全部数据, k ≤ 500000 k \le 500000 k500000 n i ≤ 1 0 9 n_i \le 10^9 ni109

又是参加学校每日题的一天,熟练的点开了题目的算法标签,想看看这个题我有没有一点点涉猎(又是及时放弃的一天(bushi))一看:博弈论。瞬间想起了之前在b站刷到过却放在收藏夹吃灰,于是决定好好看看而不是直接放弃(

让我们分析分析这道题。经典的Nim游戏 P2197 【模板】Nim 游戏
首先我们需要认识到,仅有一堆棋子存在时,出现胜负决断
在这里插入图片描述

n=1: 先手全拿,先手必胜。

n=2:有两种情况,一种可能相同,一种情况一堆比另一堆少(多)

    (m,m) 按照“有一学一,照猫画猫”法,先手必输。(m,M)先手先从多的一堆中拿出(M-m)个,此时后手面对(m,m)的局面先手必胜。

术语:正经人称(m,m)的局面为奇异局势
n=3:(m,m,M)先手必胜局,先手可以先拿M,之后变成了(m,m,0)的局面,是不是很熟悉~

(a1,a2,a3)的话,举个例子(1,2,3),先手取完之后可能的局面为(0,2,3),(1,1,3),(1,0,3),(1,2,2),(1,2,1),(1,2,0)都是之前讲过的,情况如下:
在这里插入图片描述
在这里插入图片描述
这些的结果可以总结为:异或均为0

这块的异或到底是怎么蹿出来的,我觉得洛谷题解有一篇说的挺有意思

异或有一个特殊的规律,就是一堆数异或时,若在同一个二进制位上1的个数是偶数,那么这一位异或起来以后是0,否则为1

二进制的话就是可以使用0/1表示所有数字

我们来看上一个游戏,我们将这两堆的剩余的火柴数转变成二进制。

发现我们先手取走一个数,就是改变其二进制为上的1的个数(只考虑奇偶性),而后手再去取的话就是将其奇偶性再变回来

然后我们再回去看为什么异或和是0时先手必输,因为先手拿走了某些火柴时,我们可以根据其拿走火柴的二进制表示,在其他一堆中拿走一些一些数字,使得其异或和重新为0;

怎么搞呢? 我们可以拿走一些数,也就是减某一个数,使得先手拿完后,(啰嗦警告)

所有堆中的每个二进制上的一的个数的和,我们总可以通过加减一个数,达到在某一个二进制位的1的个数进行加一or减一的效果

使得某一位二进制上的1的个数变为偶数。

从而使得游戏又恢复到了一开始的局面
题解

在这里插入图片描述
在这里插入图片描述
先手必胜,即先手可以拿走一些火柴,使得后手必败,而必败态是火柴堆的异或和为零;那么我们求的,就是先手拿走一些火柴后,新的火柴堆异或和为零的方案。设原异或和为X
在这里插入图片描述
在这里插入图片描述
当(a2 xor X)<a2时,能取走火柴。

#include <iostream>
#include<algorithm>using namespace std;
int k, n[500100], x;int main()
{cin >> k;for (int i = 1; i <= k; i++){cin >> n[i];x ^= n[i];}if (x == 0) { cout << "lose"; return 0; }for (int i = 1; i <= k; i++){if ((n[i] ^ x) < n[i]){cout << n[i] - (n[i] ^ x) << " " << i << endl;n[i] = n[i] ^ x;break;}}for (int i = 1; i <= k; i++){cout << n[i] << " ";}return 0;
}

这里贴一下感觉比较推荐的有关文章
数学知识——博弈论(巴什博奕、尼姆博奕、威佐夫博奕)思路及例题
题解 P1247 【取火柴游戏】
[学习笔记] (博弈论)Nim游戏和SG函数

相关文章:

  • 【Linux学习】进程间通信 (3) —— System V (1)
  • pygame raycasting纹理
  • 整理好了!2024年最常见 20 道 Rocket MQ面试题(一)
  • JavaScript面试 题
  • JavaScript与版本控制:编译时光机的双重奏——git仓库
  • redis基本数据结构与应用
  • 【vue-1】vue入门—创建一个vue应用
  • vue+echart :点击趋势图中的某一点或是柱状图,出现弹窗,并传输数据
  • 淘宝扭蛋机小程序:探索未知,扭出惊喜
  • (C11) 泛型表达式
  • 【ArcGISPro】CSMPlugins文件夹
  • hubilder Android模拟器华为手机连接不上
  • Unity实现首行缩进两个字符
  • Linux管理文本文件002
  • 从了解到掌握 Spark 计算框架(一)Spark 简介与基础概念
  • 【腾讯Bugly干货分享】从0到1打造直播 App
  • CAP 一致性协议及应用解析
  • Computed property XXX was assigned to but it has no setter
  • Git学习与使用心得(1)—— 初始化
  • JDK9: 集成 Jshell 和 Maven 项目.
  • Perseus-BERT——业内性能极致优化的BERT训练方案
  • PHP的Ev教程三(Periodic watcher)
  • Promise初体验
  • Promise面试题2实现异步串行执行
  • TCP拥塞控制
  • Tornado学习笔记(1)
  • 搭建gitbook 和 访问权限认证
  • 第2章 网络文档
  • 动态规划入门(以爬楼梯为例)
  • 码农张的Bug人生 - 见面之礼
  • 如何使用 JavaScript 解析 URL
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 使用parted解决大于2T的磁盘分区
  • 王永庆:技术创新改变教育未来
  • 写给高年级小学生看的《Bash 指南》
  • 白色的风信子
  • 【干货分享】dos命令大全
  • Salesforce和SAP Netweaver里数据库表的元数据设计
  • $nextTick的使用场景介绍
  • (04)Hive的相关概念——order by 、sort by、distribute by 、cluster by
  • (12)目标检测_SSD基于pytorch搭建代码
  • (51单片机)第五章-A/D和D/A工作原理-A/D
  • (二)JAVA使用POI操作excel
  • (附源码)spring boot球鞋文化交流论坛 毕业设计 141436
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (五十)第 7 章 图(有向图的十字链表存储)
  • (游戏设计草稿) 《外卖员模拟器》 (3D 科幻 角色扮演 开放世界 AI VR)
  • (转)Android中使用ormlite实现持久化(一)--HelloOrmLite
  • (转)EXC_BREAKPOINT僵尸错误
  • .[hudsonL@cock.li].mkp勒索加密数据库完美恢复---惜分飞
  • .NET C# 使用GDAL读取FileGDB要素类
  • .net 发送邮件
  • .NET 中使用 TaskCompletionSource 作为线程同步互斥或异步操作的事件
  • .NET/C# 中设置当发生某个特定异常时进入断点(不借助 Visual Studio 的纯代码实现)
  • .NetCore项目nginx发布