Portal -->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\)值为:

\[(x\% i=奇数?sg(\lfloor\frac{x}{i}\rfloor+1):0)\wedge(i-x\%i=奇数?sg(\lfloor\frac{x}{i}\rfloor):0)
\]

​​   具体的话就是因为如果是偶数那一部分全部异或起来就是\(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】江南乐的更多相关文章

  1. BZOJ-3576 江南乐 博弈+优化

    fye测试原题,高一全跪,高二学长除了CA爷似乎都A辣(逃) 3576: [Hnoi2014]江南乐 Time Limit: 30 Sec Memory Limit: 512 MB Submit: 1 ...

  2. bzoj 3576[Hnoi2014]江南乐 sg函数+分块预处理

    3576: [Hnoi2014]江南乐 Time Limit: 30 Sec  Memory Limit: 512 MBSubmit: 1929  Solved: 686[Submit][Status ...

  3. 【BZOJ3576】江南乐(博弈论)

    [BZOJ3576]江南乐(博弈论) 题面 BZOJ 洛谷 题解 无论一堆石头怎么拆分,都并不能改变它是一个\(Multi-SG\)的事实. 既然每一组的\(F\)都是固定的,那么我们预处理所有的可能 ...

  4. 洛谷 P3235 [HNOI2014]江南乐 解题报告

    P3235 [HNOI2014]江南乐 Description 两人进行 T 轮游戏,给定参数 F ,每轮给出 N 堆石子,先手和后手轮流选择石子数大于等于 F 的一堆,将其分成任意(大于1)堆,使得 ...

  5. 【LOJ】#2210. 「HNOI2014」江南乐

    LOJ#2210. 「HNOI2014」江南乐 感觉是要推sg函数 发现\(\lfloor \frac{N}{i}\rfloor\)只有\(O(\sqrt{N})\)种取值 考虑把这些取值都拿出来,能 ...

  6. bzoj3576: [Hnoi2014]江南乐

    Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏.    游戏的规则是这样的,首先给定一 ...

  7. BZOJ 3576 江南乐

    http://www.lydsy.com/JudgeOnline/problem.php?id=3576 思路:由于数字巨大,因此N^2异或做法是过不了的,我们考虑将n个石子分成i堆,那么会有n%i堆 ...

  8. [HNOI 2014]江南乐

    Description 题库链接 给你指定一个数 \(f\) ,并给你 \(T\) 组游戏,每组有 \(n\) 堆石子, \(A,B\) 两人轮流对石子进行操作,每次你可以选择其中任意一堆数量不小于 ...

  9. [HNOI2014]江南乐

    Description 小A是一个名副其实的狂热的回合制游戏玩家.在获得了许多回合制游戏的世界级奖项之后,小A有一天突然想起了他小时候在江南玩过的一个回合制游戏.    游戏的规则是这样的,首先给定一 ...

随机推荐

  1. [转]git学习------>git-rev-parse命令初识

    git学习------>git-rev-parse命令初识 2017年06月13日 10:04:13 阅读数:2172 一.准备工作 第一步:在d盘git test目录下,新建工作区根目录dem ...

  2. 使用PHP写ajax接口

    使用PHP写ajax接口 之前有学过php都是前后端没有分离的,所以也想去了解后端是怎么写出ajax接口的,可能问了别人或者上网找了很多资料都很有有点懵,或者说直接用TP或者lavarel这些后端框架 ...

  3. 420. Count and Say【LintCode java】

    Description The count-and-say sequence is the sequence of integers beginning as follows: 1, 11, 21, ...

  4. kubeadm构建k8s之Prometheus-operated监控(0.18.1)

    介绍: 大家好,k8s的搭建有许多方式,也有许多快速部署的,为了简化部署的复杂度,官方也提供了开源的kubeadm快速部署,最新1.10.x版本已经可以实现部署集群, 如果你对k8s的原理已经非常了解 ...

  5. sqli-labs学习笔记 DAY3

    DAY 3 sqli-labs lesson 6 同lesson 5,只是把单引号改为双引号 sqli-labs lesson 7 同lesson 5,只是把单引号后面加两个空格,使用Burpsuit ...

  6. 利用Tensorflow进行自然语言处理(NLP)系列之二高级Word2Vec

    本篇也同步笔者另一博客上(https://blog.csdn.net/qq_37608890/article/details/81530542) 一.概述 在上一篇中,我们介绍了Word2Vec即词向 ...

  7. 4. 基本socket函数

    一.创建socket /* 创建一个socket */ int socket(int family, int type, int protocol); /* 参数说明 */ // domain:使用哪 ...

  8. 基础系列(6)—— C#类和对象

    一.类介绍       类(class)是C#类型中最基础的类型.类是一个数据结构,将状态(字段)和行为(方法和其他函数成员)组合在一个单元中.类提供了用于动态创建类实例的定义,也就是对象(objec ...

  9. 缓存-MemoryCache Class

    这是使用MemoryCache缓存的一个例子. private void btnGet_Click(object sender, EventArgs e) { ObjectCache cache = ...

  10. webpack打包多html开发案例新

    闲来无事在原来简单打包案例的基础上,参考vue-cli的打包代码,改为多文件打包. 区别于上篇文章<webpack打包多html开发案例>,此次打包根据开发的不同环节进行打包,也就是有开发 ...