博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
【bzoj3567】江南乐
阅读量:4670 次
发布时间:2019-06-09

本文共 2674 字,大约阅读时间需要 8 分钟。

Solution

​   今天开始啃博弈论了qwq

​   先mark一篇很棒的博客

​​   稍微总结一下两个自己容易混淆的点:

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
#include
#include
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

转载于:https://www.cnblogs.com/yoyoball/p/9424734.html

你可能感兴趣的文章
python中将函数赋值给变量时需要注意的一些问题
查看>>
SAS数据挖掘实战篇【五】
查看>>
如何成为合格的数据分析师
查看>>
ArcGIS10.5资源分享
查看>>
理解http幂等性
查看>>
grep运用
查看>>
logstash收集syslog日志
查看>>
jenkins修改数据存放路径
查看>>
poj2481树状数组解二维偏序
查看>>
软件工程网络15个人阅读作业1(201521123062 杨钧宇)
查看>>
根据控制点坐标对完成坐标转换
查看>>
Boost.ASIO简要分析-4 多线程
查看>>
java调用支付宝接口代码介绍
查看>>
安装apache 后,找不到服务,解决办法
查看>>
linux下tomcat的安装
查看>>
【洛谷 T47488】 D:希望 (点分治)
查看>>
【洛谷 P1772】 [ZJOI2006]物流运输(Spfa,dp)
查看>>
cacti监控服务器
查看>>
PostMan设置
查看>>
C#判断访问入口是移动端还是PC
查看>>