「笔记」博弈瞎写


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

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

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


xor

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

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

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

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

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

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

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

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

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

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

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

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

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

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


nimber

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

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

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

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

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

至于它为什么是域。。。

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

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

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

(2)\(2^{2^n}\otimes 2^{2^n} = \frac{3}{2}\times2^{2^n}\)

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

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

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

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

\[\begin{aligned} a\otimes b &= (M\times p_a+r_a)\times (M\times p_b+ r_b) \\ &=(\frac{3}{2}M)\times p_a\times p_b + M(p_a\times r_b+p_b \times r_a)+ r_a \times r_b \\ &=(M+ (\frac{M}{2}))\times p_a \times p_b + M((p_a + r_a)\times (p_b + r_b) + p_a\times p_b + r_a\times r_b)+r_a\times r_b \\ &= (\frac{M}{2})\times(p_a\times p_b)+M((p_a + p_b)\times (r_a + r_b) + r_a \times r_b)+r_a\times 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(\log\log 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 退役完就来补坑。

posted @ 2020-07-29 20:34  Tiw_Air_OAO  阅读(18)  评论(0编辑  收藏