[AcWing 893] 集合-Nim游戏
点击查看代码
#include<iostream>
#include<cstring>
#include<unordered_set>
using namespace std;
const int N = 110, M = 1e4 + 10;
int k, n;
int s[N], f[M];
//s存储的是可供选择的集合,f存储的是所有可能出现过的情况的sg值
int sg(int x)
{
if (f[x] != -1) return f[x];
//因为取石子数目的集合是已经确定了的,所以每个数的sg值也都是确定的,如果存储过了,直接返回即可
unordered_set<int> S;
//set代表的是有序集合(注:因为在函数内部定义,所以下一次递归中的S不与本次相同)
for (int i = 0; i < k; i ++) {
int sum = s[i];
if (x >= sum) S.insert(sg(x - sum));
//先延伸到终点的sg值后,再从后往前排查出所有数的sg值
}
for (int i = 0; ; i ++)
//循环完之后可以进行选出最小的没有出现的自然数的操作
if (!S.count(i))
return f[x] = i;
}
int main()
{
cin >> k;
for (int i = 0; i < k; i ++) cin >> s[i];
cin >> n;
memset(f, -1, sizeof f);
int res = 0;
for (int i = 0; i < n; i ++) {
int x;
cin >> x;
res ^= sg(x);
}
if (res) puts("Yes");
else puts("No");
return 0;
}
- 运算
定义 表示一个非负整数集合,定义 为:求出不属于 的最小非负整数; - 函数
在有向图游戏中,对于每个节点 ,设从 出发共有 条有向边,分别到达节点 ,则 ,特别地,对于没有后继节点的节点 ,,整个有向图 的 函数值被定义为有向图起点 的 函数值,即 - 一个有向图的情况
当只有一个有向图时,如果 ,则先手必胜,否则,先手必败
证明:如果 ,说明从 可以走到 的点,而根据 函数的定义, 的点走到的点一定满足 ,如此一来,先手必然是走到最后一个根节点的那个人,而后手将无路可走; - 多个有向图的情况
当有多个有向图时,如果 ,则先手必胜,否则,先手必败
证明:(和经典 Nim 游戏类似)
① 若 ,那么无论选哪个图,在单个图上都必败;
② 若 ,一定存在 ,使得 ,而根据 函数的定义, 一定可以走到 这个节点,这时
③ 若 ,那么无论怎么走,下一次的异或值必不为
反证法:如果要让下一次的异或值为 ,那么 一定要走到 的点,而这与 函数的定义矛盾,故下一次的异或值必不为
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!