Position:


List

Description

  • 大意:有n堆石子,每堆石子个数已知,两人轮流从中取石子,每次可取的石子数x满足x属于集合S(k) = {s1,s2,s3…sk-1},问先拿者是否有必胜策略?
  • 普通Nim取石子游戏但加了一些限制条件,比如每次只能取S={s1,s2,s3……},就把前驱的条件改一下就行。

Knowledge

Sprague-Grundy Function-SG函数–博弈论
博弈论也是最近新学的知识,上面是一个写得很好的博客。
简单脑补:对于公平博弈(一般是NIM游戏),我们有一个重要的工具————就是SG函数。
SG函数的定义:
必败态的sg值为0,其余态的sg值为其后继状态的sg值的mex和。
其中mex和操作(mex{a1,a2,a3,…,ar})的含义是a1,a2,a3,…,ar中最小的没出现过的自然数。
而对于组合游戏(就是由若干个子游戏组合而成,每个子游戏之间状态独立,每次操作任选一个子游戏操作),其sg值为所有子游戏sg值的异或和。如果一个状态求得sg值为0,则为必败态,否则为必胜态。(证明略,大致是因为先手总能通过一步使sg不为0的状态变为0,而sg为0的状态只能变成sg不为0的状态,最后不能操作的状态sg也为0)而一般sg都是打表找规律,常用分析方法:(1) 等差分析(2) 等比分析(3) 特定数值位置分析(4) 奇偶位置分析。对于多组数据都不同就要暴力求,如本题。

Solution

分析:
1.可将问题转化为n个子问题,每个子问题分别为:
从一堆x颗石子中取石子,每次可取的石子数为集合S(k)中的一个数
2.分析(1)中的每个子问题,易得:SG(x)=mex(SG[(x-s[i]>0)])(k>=i>=1)
3.后面就是SG函数的应用,根据Sprague-Grundy Therem:g(G)=g(G1)^g(G2)^g(G3)^…^g(Gn)即游戏的和的SG函数值是它的所有子游戏的SG函数值的异或,即SG(G) = SG(x1)^SG(x2)^…^SG(xn),故若SG(G)=0那么必输。

Notice

memset:①比for快②#include - cstring
map复杂度加一个log,对于加入的数少的情况用,else flag数组。

Code

// <S-Nim.cpp> - 08/03/16 20:18:06
// This file is made by YJinpeng,created by XuYike's black technology automatically.
// Copyright (C) 2016 ChangJun High School, Inc.
// I don't know what this program is. #include <iostream>
#include <vector>
#include <algorithm>
#include <cstring>
#include <cstdio>
#include <map>
#include <cstdlib>
#include <cmath>
#define MOD 1000000007
#define INF 1e9
#define EPS 1e-10
using namespace std;
typedef long long LL;
const int MAXN=;
const int MAXM=;
inline int max(int &x,int &y) {return x>y?x:y;}
inline int min(int &x,int &y) {return x<y?x:y;}
inline int getint() {
register int w=,q=;register char ch=getchar();
while((ch<''||ch>'')&&ch!='-')ch=getchar();
if(ch=='-')q=,ch=getchar();
while(ch>=''&&ch<='')w=w*+ch-'',ch=getchar();
return q?-w:w;
}
int n,T,sg[MAXN],m,ans,s[MAXN];
inline int mex(int x){
//map<int,bool>f;
bool f[MAXN];
memset(f,,sizeof(f));//fast <cstring>
int temp;
for(int i=;i<=n;i++){
temp=x-s[i];
if(temp>=){
if(sg[temp]==-)sg[temp]=mex(temp);
f[sg[temp]]=;
}
}
for(int i=;;i++)if(!f[i])return i;
}
inline int SG(int x){
if(sg[x]==-)sg[x]=mex(x);
return sg[x];
}
int main()
{
freopen("S-Nim.in","r",stdin);
freopen("S-Nim.out","w",stdout);
while(n=getint(),n){
for(int i=;i<=n;i++)s[i]=getint();
sg[]=;
for(int i=;i<MAXN;i++)sg[i]=-;
T=getint();
while(T--){
m=getint();ans=;
while(m--)ans^=SG(getint());
if(ans)printf("W");else printf("L");
}
printf("\n");
}
return ;
}

最新文章

  1. Thinkcmf:页面常用函数
  2. Struts2 有关于无法正常的使用通配符
  3. 1-03 Sql Sever 的身份验证模式
  4. Python 2.7_Second_try_爬取阳光电影网_获取电影下载地址并写入文件 20161207
  5. java_ant详解
  6. pstack使用和原理
  7. 500G JAVA视频网盘分享 (Jeecg社区)
  8. Hibernate缓存杂谈
  9. xp下删除windows7,无法删除windows7文件夹,无法删除windows7文件,双系统卸载,取得文件权限
  10. log4j.xml配置示例
  11. Spring Aop 应用实例与设计浅析
  12. Codeforce E. Fire
  13. 通过js添加的元素点击事件无法触发
  14. iOS客户端图片智能裁剪
  15. open file /var/mobile/Media/DCIM 相册中获取到的视频地址使用 报错 视频文件不存在
  16. HDU1285确定比赛名次
  17. 在ASP.NET MVC中使用Area区域
  18. oracle having字句
  19. cocos 2dx 通过循环实现界面图形的摆放
  20. 【12】外观模式(Facade Pattern)

热门文章

  1. 在CorelDRAW中的自定义彩虹笔刷创建迷幻背景
  2. TCP端口状态LISTENING ESTABLISHED CLOSE_WAIT TIME_WAIT SYN_SENT
  3. WebAssembly 上手
  4. Python之TCP编程
  5. linux shell脚本学习笔记一
  6. &lt;MySQL&gt;入门七 存储过程和函数
  7. 第十一节:Web爬虫之数据存储(数据更新、删除、查询)
  8. WordCountPro,完结撒花
  9. JavaSE 学习笔记之网络编程(二十三)
  10. getContextPath和getRealPath的区别-----其实主要区别就是相对路径和绝对路径