【bzoj3567】江南乐
Solution
今天开始啃博弈论了qwq
先mark一篇很棒的博客Portal -->博弈论学习资料
稍微总结一下两个自己容易混淆的点:
1.有一类博弈论问题的主要步骤是首先将原游戏拆分成若干个独立的子游戏,然后原游戏的\(sg\)就是子游戏\(sg\)值的异或和
2.有向图游戏中,对于一个局面,它的\(sg\)是其后继局面的\(sg\)值的\(mex\)
这题的话,首先想怎么拆分
不难发现每一堆的操作其实是独立的,所以我们可以将对一堆石子进行操作看成这个游戏的子游戏
那么问题就变成了要求一堆石子数量为\(x\)的石子堆的\(sg\)值,我们考虑用这堆石子的数量来描述这个局面,那么也就是说我们现在要求\(sg(x)\)
这其实相当于一个有向图游戏
先不考虑时间和空间问题,我们想如何暴力求解\(sg(x)\),一个可行的方法就是记忆化搜索,对于当前局面\(x\),我们枚举一个\(i\)表示将这\(x\)个石子分成的堆数,那么这个后继局面的\(sg\)值就应该是\(sg(a_1)\wedge sg(a_2)\wedge sg(a_3)\wedge...\wedge sg(a_i)\),其中\(a\)表示的是分成\(i\)堆之后每堆的石子数量,然后\(sg(x)\)应该是所有的后继局面的\(sg\)值的\(mex\)
弄清楚这点之后,我们考虑分成\(i\)堆应该怎么分,根据题目要求,显然我们只能分成\(x\%i\)堆石子数量为\(\lfloor \frac{x}{i}\rfloor+1\)的,和\(i-x\%i\)堆石子数量为\(\lfloor \frac{x}{i}\rfloor\)的,那么根据异或的性质不难得出结论分成\(i\)堆的后继局面的\(sg\)值为:
\]
具体的话就是因为如果是偶数那一部分全部异或起来就是\(0\)了
那么现在我们可以写出来一个暴力,考虑如何优化这个东西
注意到里面有一个\(\lfloor \frac{x}{i}\rfloor\),然后这个东西只有\(\sqrt x\)种取值,处理这种东西我们可以用一个分段的套路(莫比乌斯反演既视感qwq),把所有\(\lfloor \frac{x}{i}\rfloor\)相同的\(i\)一起算,接下来在\(\lfloor \frac{x}{i}\rfloor\)相同的前提下,我们再考虑一下奇偶性的问题:会发现如果说\(i\)的奇偶性不变的话,那么\(x%i\)和\(i-x\%i\)的奇偶性也不会发生变化,又因为\(\lfloor \frac{x}{i}\rfloor\)相同,也就是说\(i\)奇偶性不变的话\(sg\)值也不会发生变化
那么所以,我们只要对于每一段\(\lfloor \frac{x}{i}\rfloor\)相同的\(i\),算一下\(i\)的\(sg\)再算一下\(i+1\)的\(sg\),就能够代表这里所有的情况了,总共是\(2\sqrt x\)个数,记忆化搜索一波,问题不大
最后是一些实现上的小细节,如果说求\(mex\)是暴力求的话,我们不能够在递归的时候每次都将判断的数组重置,所以考虑用一个打标记的方式来判,具体就是每次赋成一个不同的\(mark\)值就好了,但是这里有一个问题就是一旦采取这样的方式,在开始统计之后就不能再进行递归操作,所以我们应该在统计之前先递归一遍把这\(2\sqrt x\)个\(sg\)算出来,要注意因为中间可能会递归到自己,所以一开始要先把\(x\)的\(sg\)值赋成\(0\),防止。。一直递归下去qwq
当然啦如果你写的是递推版本就没有那么多麻烦事了qwq
代码大概长这个样子
#include<iostream>
#include<cstdio>
#include<cstring>
using namespace std;
const int N=100010;
int f[N];
int vis[N];
int n,m,T,F,ans,mark;
int sg(int x){
if (f[x]!=-1) return f[x];
int tmp1,tmp2,tmp=0;
f[x]=0;//stop first
for (int i=2,pos=0;i<=x;i=pos+1){
pos=x/(x/i);
sg(x/i),sg(x/i+1);
}
++mark;
for (int i=2,pos=0;i<=x;i=pos+1){
pos=x/(x/i);
tmp=0;
tmp1=i-x%i;
tmp2=x%i;
if (tmp1&1) tmp^=f[x/i];
if (tmp2&1) tmp^=f[x/i+1];
vis[tmp]=mark;
if (x/(i+1)==x/i){
tmp=0;
tmp1=(i+1)-x%(i+1);
tmp2=x%(i+1);
if (tmp1&1) tmp^=f[x/(i+1)];
if (tmp2&1) tmp^=f[x/(i+1)+1];
vis[tmp]=mark;
}
}
for (int i=0;i<=x;++i)
if (vis[i]!=mark){f[x]=i;return f[x];}
}
int main(){
#ifndef ONLINE_JUDGE
freopen("a.in","r",stdin);
#endif
int x;
scanf("%d%d",&T,&F);
for (int i=F;i<N;++i) f[i]=-1;
for (int o=1;o<=T;++o){
scanf("%d",&n);
ans=0;
for (int i=1;i<=n;++i){
scanf("%d",&x);
ans^=sg(x);
}
if (ans==0) printf("%d ",0);
else printf("%d ",1);
}
}
【bzoj3567】江南乐的更多相关文章
- BZOJ-3576 江南乐 博弈+优化
fye测试原题,高一全跪,高二学长除了CA爷似乎都A辣(逃) 3576: [Hnoi2014]江南乐 Time Limit: 30 Sec Memory Limit: 512 MB Submit: 1 ...
- bzoj 3576[Hnoi2014]江南乐 sg函数+分块预处理
3576: [Hnoi2014]江南乐 Time Limit: 30 Sec Memory Limit: 512 MBSubmit: 1929 Solved: 686[Submit][Status ...
- 【BZOJ3576】江南乐(博弈论)
[BZOJ3576]江南乐(博弈论) 题面 BZOJ 洛谷 题解 无论一堆石头怎么拆分,都并不能改变它是一个\(Multi-SG\)的事实. 既然每一组的\(F\)都是固定的,那么我们预处理所有的可能 ...
- 洛谷 P3235 [HNOI2014]江南乐 解题报告
P3235 [HNOI2014]江南乐 Description 两人进行 T 轮游戏,给定参数 F ,每轮给出 N 堆石子,先手和后手轮流选择石子数大于等于 F 的一堆,将其分成任意(大于1)堆,使得 ...
- 【LOJ】#2210. 「HNOI2014」江南乐
LOJ#2210. 「HNOI2014」江南乐 感觉是要推sg函数 发现\(\lfloor \frac{N}{i}\rfloor\)只有\(O(\sqrt{N})\)种取值 考虑把这些取值都拿出来,能 ...
- bzoj3576: [Hnoi2014]江南乐
Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏. 游戏的规则是这样的,首先给定一 ...
- BZOJ 3576 江南乐
http://www.lydsy.com/JudgeOnline/problem.php?id=3576 思路:由于数字巨大,因此N^2异或做法是过不了的,我们考虑将n个石子分成i堆,那么会有n%i堆 ...
- [HNOI 2014]江南乐
Description 题库链接 给你指定一个数 \(f\) ,并给你 \(T\) 组游戏,每组有 \(n\) 堆石子, \(A,B\) 两人轮流对石子进行操作,每次你可以选择其中任意一堆数量不小于 ...
- [HNOI2014]江南乐
Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏. 游戏的规则是这样的,首先给定一 ...
随机推荐
- centos下JDK安装及环境变量配置
由于centos安装自带openjdk,需要将其卸载后安装自己的jdk 卸载centos自带jdk 1.查找java :rpm -qa | grep java 2.卸载时提示权限不够,进入root目录 ...
- IDE看代码,挺好
初学编程的时候总是收到各种警告:“刚学习编程千万不要用IDE,否则会有xxxxxx的后果”.现在工作后发现使用IDE可以方便编写和查看代码,对于较大的项目来说有很多代码,代码之间的关系也比较复杂,ID ...
- HDU-6315:Naive Operations(线段树+思维)
链接:HDU-6315:Naive Operations 题意: In a galaxy far, far away, there are two integer sequence a and b o ...
- hadoop Datanode Uuid unassigned
在配置hadoop的hdfs的时候,要首先格式化,然后才能启动,但是格式化的方式有的是不对出现Initialization failed for Block pool <registering& ...
- react native中state和ref的使用
react native中state和ref的使用 因props是只读的,页面中需要交互的情况我们就需要用到state. 一.如何使用state 1:初始化state 第一种方式: construct ...
- 《Linux内核与分析》第五周
20135130王川东 一.给MenuOS增加time和time-asm命令 命令:1.强制删除:rm menu -rf 2.克隆:git clone (后跟需要克隆数据所在的位置) 3.自动编译,自 ...
- linux awk,sort,uniq,wc,cut命令详解
1.awk awk是行处理器: 相比较屏幕处理的优点,在处理庞大文件时不会出现内存溢出或是处理缓慢的问题,通常用来格式化文本信息 $ 表示当前行 $ 表示第一列 NF 表示一共有多少列 $NF 表示最 ...
- vmvare fusion 8
http://jingyan.baidu.com/article/54b6b9c0f8830f2d583b47ce.html 补充:vmware tools 在上面,直接点击安装
- 栈和队列在python中的实现
栈和队列是两种基本的数据结构,同为容器类型.两者根本的区别在于: stack:后进先出 queue:先进先出 PS:stack和queue是不能通过查询具体某一个位置的元素而进行操作的.但是他们的排列 ...
- shader language学习(1)——shader language简介背景
shader language,称为着色语言,shade在英语是阴影.颜色深浅的意思.shader language基于物体本身属性和光照条件,计算美格橡塑的颜色值. 实际上这种解释具有明显的时代局限 ...