891. Nim游戏
给定 n
堆石子,两位玩家轮流操作,每次操作可以从任意一堆石子中拿走任意数量的石子(可以拿完,但不能不拿),最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 n
。
第二行包含 n
个数字,其中第 i 个数字表示第 i
堆石子的数量。
输出格式
如果先手方必胜,则输出 Yes。
否则,输出 No。
数据范围
1≤n≤105
,
1≤每堆石子数≤109
输入样例:
- 2
- 2 3
输出样例:
Yes
* 假定石堆的数量是:S1,S2,...,Si,Sj,...,Sn;
* 1)如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么必然存在先手必败;
* 证明:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
* 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;
* 用反证法证明:假设存在 S1^S2^...^(Si-x)^Sj^...^Sn == 0,
* 因为 S1^S2^...^Si^Sj^...^Sn == 0 ,所以 S1^S2^...^Sj^...^Sn == Si;
* 所以S1^S2^...^(Si-x)^Sj^...^Sn == 0 => Si^(Si-x)==0 => Si=Si-x => x=0(与条
* 件矛盾),不成立;
* 即:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
* 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;得证。
*
* 2)如果S1^S2^...^Si^Sj^...^Sn != 0 ,那么必然存在先手必胜;
* 证明:如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
* 那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
* 能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
* 证明:取出一个数 Si-(Si^m),那么 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
* 所以:S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0
* => S1^S2^...^(Si^m)^Sj^...^Sn == 0
* => 将m提在后面: S1^S2^...^Si^Sj^...^Sn^m == 0
* 因为 S1^S2^...^Si^Sj^...^Sn == m, m^m ==0
* 所以得到 S1^S2^...^Si^Sj^...^Sn^m = m^m = 0;
* 现在来证明 Si-(Si^m) > 0;
* 证明:因为m的最高位1是在第k位,而Si的第k位一定存在1,所以Si^m之后,第k位的结果
* 一定是0;
* 所以在最极端的情况下, Si 与 Si^m 的比较:
* Si Si^m
* 第k位 1 0
* 第k位前面的位置 1/0 与Si相同
* 第k位后面的位置 1/0 不确定(但即便是 Si 取全0,Si^m取全1,两个数相
* 减也一定满足大于0);
* 得证!
* 得证!
- /**
- * 假定石堆的数量是:S1,S2,...,Si,Sj,...,Sn;
- * 1)如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么必然存在先手必败;
- * 证明:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
- * 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;
- * 用反证法证明:假设存在 S1^S2^...^(Si-x)^Sj^...^Sn == 0,
- * 因为 S1^S2^...^Si^Sj^...^Sn == 0 ,所以 S1^S2^...^Sj^...^Sn == Si;
- * 所以S1^S2^...^(Si-x)^Sj^...^Sn == 0 => Si^(Si-x)==0 => Si=Si-x => x=0(与条
- * 件矛盾),不成立;
- * 即:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
- * 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;得证。
- *
- * 2)如果S1^S2^...^Si^Sj^...^Sn != 0 ,那么必然存在先手必胜;
- * 证明:如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
- * 那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
- * 能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
- * 证明:取出一个数 Si-(Si^m),那么 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
- * 所以:S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0
- * => S1^S2^...^(Si^m)^Sj^...^Sn == 0
- * => 将m提在后面: S1^S2^...^Si^Sj^...^Sn^m == 0
- * 因为 S1^S2^...^Si^Sj^...^Sn == m, m^m ==0
- * 所以得到 S1^S2^...^Si^Sj^...^Sn^m = m^m = 0;
- * 现在来证明 Si-(Si^m) > 0;
- * 证明:因为m的最高位1是在第k位,而Si的第k位一定存在1,所以Si^m之后,第k位的结果
- * 一定是0;
- * 所以在最极端的情况下, Si 与 Si^m 的比较:
- * Si Si^m
- * 第k位 1 0
- * 第k位前面的位置 1/0 与Si相同
- * 第k位后面的位置 1/0 不确定(但即便是 Si 取全0,Si^m取全1,两个数相
- * 减也一定满足大于0);
- * 得证!
- * 得证!
- */
-
- #include
-
- using namespace std;
-
- int main()
- {
- int n;
- cin >> n;
- int res=0;
-
- while (n -- )
- {
- int val;
- cin >> val;
- res^=val;
- }
-
- if(res)
- puts("Yes");
- else
- puts("No");
-
- return 0;
- }
893. 集合-Nim游戏
给定 n
堆石子以及一个由 k 个不同正整数构成的数字集合 S
。
现在有两位玩家轮流操作,每次操作可以从任意一堆石子中拿取石子,每次拿取的石子数量必须包含于集合 S
,最后无法进行操作的人视为失败。
问如果两人都采用最优策略,先手是否必胜。
输入格式
第一行包含整数 k
,表示数字集合 S
中数字的个数。
第二行包含 k
个整数,其中第 i 个整数表示数字集合 S 中的第 i 个数 si
。
第三行包含整数 n
。
第四行包含 n
个整数,其中第 i 个整数表示第 i 堆石子的数量 hi
。
输出格式
如果先手方必胜,则输出 Yes。
否则,输出 No。
数据范围
1≤n,k≤100
,
1≤si,hi≤10000
输入样例:
- 2
- 2 5
- 3
- 2 4 7
输出样例:
Yes
/**
1.Mex运算:
设S表示一个非负整数集合.定义mex(S)为求出不属于集合S的最小非负整数运算,即:
mes(S)=min{x};
例如:S={0,1,2,4},那么mes(S)=3;
2.SG函数
在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达节点y1,y2,····yk,
定义SG(x)的后记节点y1,y2,····yk的SG函数值构成的集合在执行mex运算的结果,即:
SG(x)=mex({SG(y1),SG(y2)····SG(yk)})
特别地,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即 SG(G)=SG(s).
3.有向图游戏的和
设G1,G2,····,Gm是m个有向图游戏.定义有向图游戏G,他的行动规则是任选某个有向图游戏Gi,并在Gi上行动一步.G被称为有向图游戏G1,G2,·····,Gm的和.
有向图游戏的和的SG函数值等于它包含的各个子游戏SG函数的异或和,即:
SG(G)=SG(G1)xorSG(G2)xor···xor SG(Gm)
以上定义是转载了一个dl的:
作者:E.lena
链接:https://www.acwing.com/solution/content/23435/
来源:AcWing
只要得到所有石堆的SG值,那么就和 Nim 游戏操作一样,将每堆石子的SG值当作 Nim游戏的
每堆石堆的数量,那么每次都可以取连接该集合的任一个方向,单是要得到最优策略,还是要
根据所有石堆的异或和来选择特定石堆的数量;
给出Nim游戏的证明后再探讨Nim集合的正确性:
* 假定石堆的数量是:S1,S2,...,Si,Sj,...,Sn;
* 1)如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么必然存在先手必败;
* 证明:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
* 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;
* 用反证法证明:假设存在 S1^S2^...^(Si-x)^Sj^...^Sn == 0,
* 因为 S1^S2^...^Si^Sj^...^Sn == 0 ,所以 S1^S2^...^Sj^...^Sn == Si;
* 所以S1^S2^...^(Si-x)^Sj^...^Sn == 0 => Si^(Si-x)==0 => Si=Si-x => x=0(与条
* 件矛盾),不成立;
* 即:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
* 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;得证。
*
* 2)如果S1^S2^...^Si^Sj^...^Sn != 0 ,那么必然存在先手必胜;
* 证明:如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
* 那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
* 能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
* 证明:取出一个数 Si-(Si^m),那么 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
* 所以:S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0
* => S1^S2^...^(Si^m)^Sj^...^Sn == 0
* => 将m提在后面: S1^S2^...^Si^Sj^...^Sn^m == 0
* 因为 S1^S2^...^Si^Sj^...^Sn == m, m^m ==0
* 所以得到 S1^S2^...^Si^Sj^...^Sn^m = m^m = 0;
* 现在来证明 Si-(Si^m) > 0;
* 证明:因为m的最高位1是在第k位,而Si的第k位一定存在1,所以Si^m之后,第k位的结果
* 一定是0;
* 所以在最极端的情况下, Si 与 Si^m 的比较:
* Si Si^m
* 第k位 1 0
* 第k位前面的位置 1/0 与Si相同
* 第k位后面的位置 1/0 不确定(但即便是 Si 取全0,Si^m取全1,两个数相
* 减也一定满足大于0);
* 得证!
* 得证!
因为我们在Nim游戏的证明中证明出了:
如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;且Si-(Si^m) > 0,所以在Nim集合中,
我们能得出,SG1^SG2^...^SGi^...^SGn !=0 ==m 的时候,我们可以选择第i个集合里选择第
SGi-(SGi^m) 条路线,(此路线一定存在,因为SGi-(SGi^m)
SG1^SG2^...^SGi^...^SGn == 0,就不消证明,先手必输;
*/
- /**
- 1.Mex运算:
- 设S表示一个非负整数集合.定义mex(S)为求出不属于集合S的最小非负整数运算,即:
- mes(S)=min{x};
- 例如:S={0,1,2,4},那么mes(S)=3;
- 2.SG函数
- 在有向图游戏中,对于每个节点x,设从x出发共有k条有向边,分别到达节点y1,y2,····yk,
- 定义SG(x)的后记节点y1,y2,····yk的SG函数值构成的集合在执行mex运算的结果,即:
- SG(x)=mex({SG(y1),SG(y2)····SG(yk)})
- 特别地,整个有向图游戏G的SG函数值被定义为有向图游戏起点s的SG函数值,即 SG(G)=SG(s).
- 3.有向图游戏的和
- 设G1,G2,····,Gm是m个有向图游戏.定义有向图游戏G,他的行动规则是任选某个有向图游戏Gi,并在Gi上行动一步.G被称为有向图游戏G1,G2,·····,Gm的和.
- 有向图游戏的和的SG函数值等于它包含的各个子游戏SG函数的异或和,即:
- SG(G)=SG(G1)xorSG(G2)xor···xor SG(Gm)
- 以上定义是转载了一个dl的:
- 作者:E.lena
- 链接:https://www.acwing.com/solution/content/23435/
- 来源:AcWing
- 只要得到所有石堆的SG值,那么就和 Nim 游戏操作一样,将每堆石子的SG值当作 Nim游戏的
- 每堆石堆的数量,那么每次都可以取连接该集合的任一个方向,单是要得到最优策略,还是要
- 根据所有石堆的异或和来选择特定石堆的数量;
- 给出Nim游戏的证明后再探讨Nim集合的正确性:
- * 假定石堆的数量是:S1,S2,...,Si,Sj,...,Sn;
- * 1)如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么必然存在先手必败;
- * 证明:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
- * 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;
- * 用反证法证明:假设存在 S1^S2^...^(Si-x)^Sj^...^Sn == 0,
- * 因为 S1^S2^...^Si^Sj^...^Sn == 0 ,所以 S1^S2^...^Sj^...^Sn == Si;
- * 所以S1^S2^...^(Si-x)^Sj^...^Sn == 0 => Si^(Si-x)==0 => Si=Si-x => x=0(与条
- * 件矛盾),不成立;
- * 即:如果S1^S2^...^Si^Sj^...^Sn == 0 ,那么在Si中取出一个数 x(>0) 后,
- * 必然满足 S1^S2^...^(Si-x)^Sj^...^Sn != 0 ;得证。
- *
- * 2)如果S1^S2^...^Si^Sj^...^Sn != 0 ,那么必然存在先手必胜;
- * 证明:如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
- * 那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
- * 能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
- * 证明:取出一个数 Si-(Si^m),那么 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;
- * 所以:S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0
- * => S1^S2^...^(Si^m)^Sj^...^Sn == 0
- * => 将m提在后面: S1^S2^...^Si^Sj^...^Sn^m == 0
- * 因为 S1^S2^...^Si^Sj^...^Sn == m, m^m ==0
- * 所以得到 S1^S2^...^Si^Sj^...^Sn^m = m^m = 0;
- * 现在来证明 Si-(Si^m) > 0;
- * 证明:因为m的最高位1是在第k位,而Si的第k位一定存在1,所以Si^m之后,第k位的结果
- * 一定是0;
- * 所以在最极端的情况下, Si 与 Si^m 的比较:
- * Si Si^m
- * 第k位 1 0
- * 第k位前面的位置 1/0 与Si相同
- * 第k位后面的位置 1/0 不确定(但即便是 Si 取全0,Si^m取全1,两个数相
- * 减也一定满足大于0);
- * 得证!
- * 得证!
- 因为我们在Nim游戏的证明中证明出了:
- 如果S1^S2^...^Si^Sj^...^Sn !=0 ==m,假设m用二进制表示的1的最高位是第k位,
- 那么至少存在一个数字Si,使得Si用二进制表示的数的第k位是1,取出一个数 Si-(Si^m)
- 能使得 S1^S2^...^(Si-(Si-(Si^m))^Sj^...^Sn == 0;且Si-(Si^m) > 0,所以在Nim集合中,
- 我们能得出,SG1^SG2^...^SGi^...^SGn !=0 ==m 的时候,我们可以选择第i个集合里选择第
- SGi-(SGi^m) 条路线,(此路线一定存在,因为SGi-(SGi^m)
- 所以必定存在 SGi-(SGi^m) 属于 [0,SGi);
- SG1^SG2^...^SGi^...^SGn == 0,就不消证明,先手必输;
- */
-
-
- #include
- #include
- #include
-
- using namespace std;
-
- const int maxn = 10010;
- int hs[maxn],f[maxn];
- int m;
-
- int SG(int val)
- {
- if(hs[val]!=-1) //如果val块石子的石堆处理过,直接返回
- return hs[val];
-
- set<int> st;
- for(int i=0;i
- {
- int sum=f[i];
- if(val>=sum)
- st.insert(SG(val-sum));
- }
-
- for(int i=0; ;++i)
- if(!st.count(i)) //只要有最小不等于该集合的非负整数,就赋给hs[val];
- return hs[val]=i;
- }
-
- int main()
- {
- cin >> m;
- for(int i=0;i
- cin >> f[i];
-
- memset(hs,-1,sizeof(hs)); //将所有集合都初始化为-1,表示未被处理
-
- int n;
- cin >> n;
-
- int res=0;
- for(int i=0;i
- {
- int val;
- cin >> val;
- res^=SG(val);
- }
-
- if(res) //如果异或和不为0
- puts("Yes");
- else
- puts("No");
-
- return 0;
- }
-
相关阅读:
开放词汇视觉定位 OV-VG: A Benchmark for Open-Vocabulary Visual Grounding 论文笔记
数组名和&数组名
【华为OD统一考试B卷 | 100分】单词接龙(C++ Java JavaScript Python)
05 | 基础篇:某个应用的CPU使用率居然达到100%,我该怎么办?笔记
Paillier算法简介
Mac OS 使用ScreenCaptureKit进行窗口抓取和系统声音抓取
2025~《数据结构》试题~考研
NLP(六十七)BERT模型训练后动态量化(PTDQ)
使用 RAG、Langchain 和 Streamlit 制作用于文档问答的 AI 聊天机器人
c语言,c++,java和python这些语言有何区别?编译型编程语言编译语言,解释型编程语言解释型语言
-
原文地址:https://blog.csdn.net/qq_51825761/article/details/126352961