「笔记」博弈瞎写


想了想还是给这种 blog 取名叫「笔记」比较好。感觉细品来是个很有诗意的名字(我差点就信了)。

没什么干货,基本上都是瞎写,而且是想到什么写什么,所以可能你看完也学习不到什么。

由于我数学很差,所以可能会写大堆废话 + 大堆错误 + 大堆不带证明的结论。


xor

为什么 nim 游戏会与 xor 扯上关系?(虽然就 “验证正确性” 而言这是显然归纳法可证的。。。)

灵感来自于知乎里面的这篇问答。由于知乎的数学公式排版有点难受,所以就自己再梳理了一遍。

首先,我们重新定义 xor 为域 (mathrm{Z/2Z}) 上的线性空间的向量加。相信聪明的读者读到这里已经恍然大悟了,剩下的留作习题。

以下记 (f(a_1,a_2dots a_k)) 表示当前 nim 游戏的 np 状态,其中 (a_i) 是第 (i) 堆石子的状态。

现在我们想找到 (1) 堆石子 (b) 等效替代 ({a_i}),那么有 (f(b)=f(a_1,a_2dots a_k)),由此简化了问题。

为了处理的方便,我们定义 ({a_i})({b_i}) 等效当且仅当 (forall c,f(a_1,a_2dots a_p,c) = f(b_1,b_2,dots,b_q,c)),容易验证这是等价关系。

在等价类之间定义运算 (Aoplus B = C),表示把等价类 (A) 与等价类 (B) 组合得到等价类 (C)。这个运算满足:

(1)交换律 (Aoplus B = Boplus A),显然该运算并没有顺序要求。

(2)结合律 ((Aoplus B)oplus C = Aoplus(Boplus C)),由 “等效” 的定义可知。

(3)幺元 (0oplus A = A),显然,因为玩家无法操作没有石子的石堆。

(4)逆元 (Aoplus A = 0),由 nim 游戏的对称性策略可得。

也即它是阿贝尔群。事实上,最后一点还说明该群所有元素(除了幺元)都是二阶元素,因此该群同构于一列二阶群的直积。

然后,你发现 xor 也同构于一列二阶群的直积。。。

然后我实在编不下去了,所以暂时留坑吧(


nimber

草nimber这个名字(nim+number)是哪个人才想到的。

定义域 (F = (N,oplus,otimes)),其中 (oplus) 被称为 nim 和,(otimes) 被称为 nim 积。

(x oplus y) 递归定义为 (mathrm{mex}({xoplus b|b<y}cup{aoplus y|a<x}))

(xotimes y) 递归定义为 (mathrm{mex}({(xotimes b)oplus(aotimes y)oplus(aotimes b) |a<x,b<y}))

nim 和的意义是直观的,nim 积的意义。。。可以参考 hdu - 3404

至于它为什么是域。。。

nim 和的快速求解方法就是 xor,在上面已经有讨论过了。

考虑 nim 积怎么快速求解,先甩几个我也不会证的结论:

(1)(2^{2^n}otimes a = 2^{2^n} imes a(a < 2^{2^n}))

(2)(2^{2^n}otimes 2^{2^n} = frac{3}{2} imes2^{2^n})

(3)(aotimes b < 2^{2^n} (a < 2^{2^n},b<2^{2^n}))

最后一条实际上保证了在 (<2^{2^n})(F'(S,oplus,otimes)) 形成子域,此时 nim 积逆元可以直接由群论中的拉格朗日定理得到。

如果记 (a=M imes p_a+r_a,b=M imes p_b+ r_b),其中 (p_a,p_b,r_a,r_b<M=2^{2^n})。注意到这里的 ( imes,+)(otimes,oplus) 结果一致。

为了公式的美观,下文中的 (otimes,oplus) 全部写成 ( imes,+)。原本的 ( imes) 省略不写。

[egin{aligned} aotimes b &= (M imes p_a+r_a) imes (M imes p_b+ r_b) \ &=(frac{3}{2}M) imes p_a imes p_b + M(p_a imes r_b+p_b imes r_a)+ r_a imes r_b \ &=(M+ (frac{M}{2})) imes p_a imes p_b + M((p_a + r_a) imes (p_b + r_b) + p_a imes p_b + r_a imes r_b)+r_a imes r_b \ &= (frac{M}{2}) imes(p_a imes p_b)+M((p_a + p_b) imes (r_a + r_b) + r_a imes r_b)+r_a imes r_b end{aligned} ]

中间部分用了分治乘法的技巧,注意 (oplus) 的逆运算就是它自己。

由于 (p_a,p_b,r_a,r_b<M=2^{2^n}),所以可以递归到更小的子问题。可以部分记忆化一下优化常数。

时间复杂度 (T(n)=4T(n-1)=4^n),而 (n=O(loglog a)),所以 (T(a) = O(log^2 a))

typedef unsigned long long ull;

struct nimber{
	ull x; nimber() {} nimber(ull _x) : x(_x) {}
	
	friend nimber operator + (const nimber &a, const nimber &b) {
		return nimber(a.x ^ b.x);
	}
	friend nimber mul(const nimber &a, const nimber &b, int L) {
		if( a.x <= 1 || b.x <= 1 ) return a.x * b.x;
		
		ull M = (1ull << L);
		nimber pa = (a.x >> L), ra = (a.x & (M - 1));
		nimber pb = (b.x >> L), rb = (b.x & (M - 1));
		if( pa.x == 0 && pb.x == 0 ) return mul(a, b, L >> 1);
		
		nimber p = mul(pa, pb, L >> 1), q = mul(pa + ra, pb + rb, L >> 1), r = mul(ra, rb, L >> 1);
		return mul(M >> 1, p, L >> 1) + nimber(M * (q + r).x) + r;
	}
	friend nimber operator * (const nimber &a, const nimber &b) {
		return mul(a, b, 32);
	}
	friend nimber mpow(nimber a, ull p) {
		nimber r; for(r = 1; p; p >>= 1, a = a * a)
			if( p & 1 ) r = r * a;
		return r;
	}
	friend nimber operator / (const nimber &a, const nimber &b) {
		return a * mpow(b, (ull)-2);
	}
};

最后放一张 wiki 上关于 nim 积的图片吧。数学真美啊.jpg。


surreal number(咕)

等我 noi2020 退役完就来补坑。


fibonacci(咕)

看到 snoi2020 有一道这样的题,于是就给自己挖了个这样一个坑。

所以同上,等我 noi2020 退役完就来补坑。

原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13399469.html