IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> P4279 [SHOI2008]小约翰的游戏(博弈论)(Anti-SG) -> 正文阅读

[C++知识库]P4279 [SHOI2008]小约翰的游戏(博弈论)(Anti-SG)

解析

我的做法:打表,哦…过了

打表观察的结论:只要不全是1,答案和正常Nim游戏相同,全是1简单讨论奇偶性即可。

证明:
全是1的正确性显然,现在考虑不全是1的时候为什么直接看异或和就行。

关键性质:当仅有一堆大于1的时候必胜。

因为我可以随意的调控接下来权值为1的个数的奇偶性。

同时,只要一开始不全是1,无论如何拿,这个状态都是必然要经历的。
因此,我们可以把它作为一个获胜的终止状态。
此时显然异或和不为0。
那么就和传统Nim的证明一样了,胜方只需要一直保证到自己走时异或和不为0即可。

bonus

很有启发性的一点是,由于Nim游戏和SG函数本质的相通性,这个结论可以推广到所有类似的Anti-SG游戏中。(Anti-SG游戏的定义:决策集合为空的状态视为胜利状态。)

把SG函数当成石子数即可。
(这个玩意好像叫 Sprague Grundy - Jia Zhihao 定理)

代码

(附打表程序)

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ull unsigned long long
#define debug(...) fprintf(stderr,__VA_ARGS__)
#define ok debug("OK\n")
using namespace std;

const int N=2e5+100;
const int mod=1e9+9;
inline ll read(){
  ll x(0),f(1);char c=getchar();
  while(!isdigit(c)) {if(c=='-')f=-1;c=getchar();}
  while(isdigit(c)) {x=(x<<1)+(x<<3)+c-'0';c=getchar();}
  return x*f;
}


inline ll ksm(ll x,ll k){
  ll res(1);
  while(k){
    if(k&1) res=res*x%mod;
    x=x*x%mod;
    k>>=1;
  }
  return res;
}
int n,m;
int a[20];
int bas=31;
inline ull Hash(int *a,int n){
  ull res=0;
  for(int i=1;i<=n;i++) res=res*bas+a[i];
  return res;
}
map<ull,int>mp;
bool cmp(int x,int y){return x>y;}
int find(const int *x,int n){
  int a[20];
  memcpy(a,x,sizeof(int)*(n+1));
  sort(a+1,a+1+n,cmp);
  while(!a[n]&&n) --n;
  if(n==0) return 1;
  ull h=Hash(a,n);
  if(mp.count(h)) return mp[h];
  int res=0;
  int b[20];
  memcpy(b,a,sizeof(int)*(n+1));
  for(int i=1;i<=n;i++){
    for(int j=0;j<a[i];j++){
      b[i]=j;
      res|=find(b,n)==0;
      b[i]=a[i];
    }
  }
  return mp[h]=res;
}
int op;
int now[20];
inline int calc(int *a,int n){
  int res(0);
  for(int i=1;i<=n;i++) res^=a[i];
  return res;
}
void dfs(int k){
  if(k>m){
    int op=find(now,m);
    if(op==0&&calc(now,m)){
      for(int i=1;i<=m;i++) printf("%d ",now[i]);
      printf("(%d) op=%d",calc(now,m),op);
      puts("");
    }
    if(op==1&&calc(now,m)==0){
      for(int i=1;i<=m;i++) printf("%d ",now[i]);
      printf("(%d) op=%d",calc(now,m),op);
      puts("");
    }
    return;
  }
  for(int i=now[k-1];i<=n;i++){
    now[k]=i;
    dfs(k+1);
  }
  return;
}
void work(){
  n=read();
  int res(0),flag=1;
  for(int i=1;i<=n;i++){
    int x=read();
    res^=x;
    flag&=(x==1);
  }
  if((res==0)^flag) puts("Brother");
  else puts("John");
}

signed main(){
  #ifndef ONLINE_JUDGE
  freopen("a.in","r",stdin);
  freopen("a.out","w",stdout);
  #endif
  //n=read();int lim=read();
  //now[0]=1;
  //for(m=1;m<=lim;m++) dfs(1);
  //return 0;
  int T=read();
  while(T--) work();
  return 0;
}
//288 125 189 111 229 


  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2022-04-28 11:37:29  更:2022-04-28 11:38:51 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年5日历 -2024/5/20 21:56:34-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码