zoukankan      html  css  js  c++  java
  • 「笔记」博弈瞎写


    想了想还是给这种 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 退役完就来补坑。

  • 相关阅读:
    Objective-C中的锁及应用-13- 多线程
    Android开发技术周报 Issue#53
    Android开发技术周报 Issue#52
    Android开发技术周报 Issue#54
    Android开发技术周报 Issue#55
    Android开发技术周报 Issue#56
    Android开发技术周报 Issue#57
    Android开发技术周报 Issue#58
    Android开发技术周报 Issue#60
    Android开发技术周报 Issue#61
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/13399469.html
Copyright © 2011-2022 走看看