集合-Nim游戏(面试hard博弈论)

简介: 集合-Nim游戏(面试hard博弈论)

给定 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

输入样例:
1. 2
2. 2 5
3. 3
4. 2 4 7
输出样例:
Yes

补充:

mex运算

这是一个施加于集合的运算,表示求出这个集合中最小的没有出现过的非负整数,比如 m e x { 0 , 2 , 3 } = 1 , m e x { 1 , 2 } = 0 , m e x { } = 0 mex\{0,2,3\}=1,mex\{1,2\}=0,mex\{\}=0mex{0,2,3}=1,mex{1,2}=0,mex{}=0。


SG函数和定理

SG定理

你可能会问了,那么这些问题不是只需要一个bool数组来记录必胜或必败就可以了吗,为什么需要 SG 函数这么麻烦呢?


这时,我们就要请出SG 定理了:


一个游戏的SG 函数值等于各个游戏的 SG 函数值的Nim 和


其中,各个游戏指的是那个大的游戏中的子游戏,而Nim 和,其实也就是异或和。


思路:


计算每一堆石头的SG函数值,然后对循环res^=SG(i),res=1必胜,否则必败

int sg(int x){
    if(f[x]!=-1)return f[x];
    unordered_set<int> S;
    for(int i=0;i<m;i++)
    {
        int sum=s[i];
        if(x>=sum)S.insert(sg(x-sum));
    }
    for(int i=0;;i++)
        if(!S.count(i))
            return f[x]=i;
}

完整代码:

#include <iostream>
using namespace std;
#include <cstring>
#include <unordered_set>
#include <algorithm>
const int N=110,M=10010;
int s[N],f[M];
int n,m;
int sg(int x){
    if(f[x]!=-1)return f[x];
    unordered_set<int> S;
    for(int i=0;i<m;i++)
    {
        int sum=s[i];
        if(x>=sum)S.insert(sg(x-sum));
    }
    for(int i=0;;i++)
        if(!S.count(i))
            return f[x]=i;
}
 
int main(){
    cin>>m;
    memset(f,-1,sizeof(f));
    for(int i=0;i<m;i++)cin>>s[i];
    int res=0;
    cin>>n;
    for(int i=0;i<n;i++)
    {
        int x;
        cin>>x;
        res^=sg(x);
    }
    if(res)cout<<"Yes";
    else cout<<"No";
    return 0;
} 


相关文章
|
6月前
|
存储 安全 算法
Java 集合面试题 PDF 下载及高频考点解析
本文围绕Java集合面试题展开,详细解析了集合框架的基本概念、常见集合类的特点与应用场景。内容涵盖`ArrayList`与`LinkedList`的区别、`HashSet`与`TreeSet`的对比、`HashMap`与`ConcurrentHashMap`的线程安全性分析等。通过技术方案与应用实例,帮助读者深入理解集合类的特性和使用场景,提升解决实际开发问题的能力。文末附带资源链接,供进一步学习参考。
153 4
|
6月前
|
存储 安全 Java
Java 集合面试题从数据结构到 HashMap 源码剖析详解及长尾考点梳理
本文深入解析Java集合框架,涵盖基础概念、常见集合类型及HashMap的底层数据结构与源码实现。从Collection、Map到Iterator接口,逐一剖析其特性与应用场景。重点解读HashMap在JDK1.7与1.8中的数据结构演变,包括数组+链表+红黑树优化,以及put方法和扩容机制的实现细节。结合订单管理与用户权限管理等实际案例,展示集合框架的应用价值,助你全面掌握相关知识,轻松应对面试与开发需求。
319 3
|
安全 Java 容器
【Java集合类面试二十七】、谈谈CopyOnWriteArrayList的原理
CopyOnWriteArrayList是一种线程安全的ArrayList,通过在写操作时复制新数组来保证线程安全,适用于读多写少的场景,但可能因内存占用和无法保证实时性而有性能问题。
|
存储 安全 Java
【Java集合类面试二十五】、有哪些线程安全的List?
线程安全的List包括Vector、Collections.SynchronizedList和CopyOnWriteArrayList,其中CopyOnWriteArrayList通过复制底层数组实现写操作,提供了最优的线程安全性能。
【Java集合类面试二十八】、说一说TreeSet和HashSet的区别
HashSet基于哈希表实现,无序且可以有一个null元素;TreeSet基于红黑树实现,支持排序,不允许null元素。
【Java集合类面试二十六】、介绍一下ArrayList的数据结构?
ArrayList是基于可动态扩展的数组实现的,支持快速随机访问,但在插入和删除操作时可能需要数组复制而性能较差。
|
存储 安全 算法
Java面试题之Java集合面试题 50道(带答案)
这篇文章提供了50道Java集合框架的面试题及其答案,涵盖了集合的基础知识、底层数据结构、不同集合类的特点和用法,以及一些高级主题如并发集合的使用。
1225 1
Java面试题之Java集合面试题 50道(带答案)
|
安全 Java API
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
String常量池、String、StringBuffer、Stringbuilder有什么区别、List与Set的区别、ArrayList和LinkedList的区别、HashMap底层原理、ConcurrentHashMap、HashMap和Hashtable的区别、泛型擦除、ABA问题、IO多路复用、BIO、NIO、O、异常处理机制、反射
【Java面试题汇总】Java基础篇——String+集合+泛型+IO+异常+反射(2023版)
|
存储 Java
【Java集合类面试二十九】、说一说HashSet的底层结构
HashSet的底层结构是基于HashMap实现的,使用一个初始容量为16和负载因子为0.75的HashMap,其中HashSet元素作为HashMap的key,而value是一个静态的PRESENT对象。
【Java集合类面试三十】、BlockingQueue中有哪些方法,为什么这样设计?
BlockingQueue设计了四组不同行为方式的方法用于插入、移除和检查元素,以适应不同的业务场景,包括抛异常、返回特定值、阻塞等待和超时等待,以实现高效的线程间通信。