标签:com c++ 博弈 lin 情况 inline 一起 https math
根据\(Nim\)游戏的基本知识我们知道可以分别求出每堆石子的\(SG\)函数,然后异或在一起就是全局的\(SG\)函数了。
一个显然的转移式:
看起来很诡异,但我们仔细想想便会找到一个性质,就是\(x\)的前\(\lfloor\frac xk\rfloor+1\)位应该是一个\(0\sim \lfloor\frac xk\rfloor\)的排列!
但如果\(x\)是\(k\)的倍数时会存在例外,此时它的前\(\lfloor\frac xk\rfloor\)位是一个\(0\sim \lfloor\frac xk\rfloor-1\)的排列,因此\(SG(x)=\lfloor\frac xk\rfloor\)。
证明只需归纳即可,应该还是比较容易的。
那么我们可以列出一个简单的递推式:
主要是考虑第三种转移,直接搞复杂度是\(O(k)\)的,如果\(k\)很大可能会挂。
但我们发现对于\(\lfloor\frac xk\rfloor\)相等的连续一段其实可以放一起转移,那么就只会转移\(O(\lfloor\frac ak\rfloor)\)次。
二者一结合,复杂度就是\(O(\sqrt a)\)的,正确了。
#include<bits/stdc++.h>
#define Tp template<typename Ty>
#define Ts template<typename Ty,typename... Ar>
#define Reg register
#define RI Reg int
#define Con const
#define CI Con int&
#define I inline
#define W while
using namespace std;
int n;I int SG(CI x,CI k)//求SG函数
{
if(x<k) return 0;if(!(x%k)) return x/k;//x<k和x是k倍数的两种情况
RI y=x/k*k,d=x/k+1,t=(x-y)/d;return SG(x-max(t,1)*d,k);//x/k相同的一段一起转移
}
int main()
{
RI i,x,k,t=0;for(scanf("%d",&n),i=1;i<=n;++i) scanf("%d%d",&x,&k),t^=SG(x,k);//把每堆石子的SG函数异或起来
return puts(t?"Takahashi":"Aoki"),0;
}
【AT3939】[ARC091D] Strange Nim(博弈论)
标签:com c++ 博弈 lin 情况 inline 一起 https math
原文地址:https://www.cnblogs.com/chenxiaoran666/p/AT3939.html