参考资料:论文集2020《》罗煜翔
事实上作者只是扫了一眼 lyx 神仙的论文,以下内容全是作者找资料总结的……
无偏博弈是一种双人回合制游戏,两人轮流行动,同时局面对两个人是对称的,也就是当前的走法与当前行动的是 A 还是 B 无关。
nim 游戏是一个无偏博弈。每人轮流从一个石子堆拿走非空的石子,不能行动(当前石子堆为空)的玩家输。
斯普莱格-格隆第定理(Sprague–Grundy theorem)指出,任何一个以“不能行动的玩家输”为胜利条件的无偏博弈等价于特定大小(一般在 OI 中称为这个游戏的 函数)(在奇怪的情形下它可能是无限的,这时候需要一些序数理论,这不是我们今天讨论的重点,所以我们可以忽略无限的情况)的 nim 游戏。
从而我们可以用 nim 堆的大小来描述游戏。因为它上面有一些和实数不同的运算(事实上 nim 数里可能会有 之类的奇怪东西)(事实上全体 nim 数甚至不能称为集合,只能称为真类)
为了避免谈论序数,我们以后只谈论 内的 nim 数构成的域。可以验证它的确对下面介绍的加和乘构成域。
一个集合 连带它上面的运算 称为一个群,如果
请注意我们不要求 具有交换律。
一个集合 和上面的两个运算 称为一个域,如果
是群,而且 具有交换律
是半群,即不要求存在单位元和逆元的群
之间满足左右分配律:
我们考虑一个称为 的新游戏,它的内容是,参与者每一步都可以选择在 游戏或 游戏中走一步。它对应的 nim 数被称为 和 的 nim 和。nim 和以如下的方式定义
其中 表示一个集合中第一个没有出现的自然数。
但是其实我们都知道有一个非常简单的办法计算它:它就是 。
考虑一个称为 的新游戏,它的内容比较复杂。我们举一个例子。
在一个白色平面上, 处有一个黑点。这是一个无偏博弈,每个回合,玩家都可以选定一个黑点 和 ,反转 的颜色。不能行动者输。
如上的这个游戏就是两个 nim 游戏的 nim 积。nim 积以如下的方式定义
由于打 latex 太累,所以接下来我们会省略 。
首先有一些结论
容易验证。
我们知道 nimber 是一个域,从而我们可以使用分配律,于是我们拆分 为二进制
注意 是 的省略。注意 ,从而这个式子是合理的。问题转化为如何求 。对于 的最高位 ,我们进行下面的讨论
记 。从而有
记 。从而有
于是综上所述有
注意 是 的省略。前面一个累乘和自然数乘相同,后一个累乘大力递归就好。复杂度 。
代码如下:
xxxxxxxxxx
ll F(ll x,ll y);
ll g[64][64];
ll G(int x,int y){
if(!x||!y) return 1LL<<(x|y);
if(~g[x][y]) return g[x][y];
ll ans=1;
for(int i=0;i<64;i++) if(((x^y)>>i)&1) ans<<=1LL<<i;
for(int i=0;i<64;i++) if(((x&y)>>i)&1) ans=F(ans,(3LL<<(1<<i))>>1);
return g[x][y]=ans;
}
ll f[256][256];
ll F(ll x,ll y){
if(!x||!y) return x|y;
if(x<256&&y<256) if(~f[x][y]) return f[x][y];
ll ans=0;
for(int i=0;i<64;i++) if((x>>i)&1)
for(int j=0;j<64;j++) if((x>>j)&1)
ans^=g(i,j);
if(x<256&&y<256) f[x][y]=ans;
return ans;
}
科技改变生活(
令一个比较好地把 均匀分为两半的 为 。我们记 。从而有
看似要计算 ,但其实不然,我们可以把 写为
从而这部分只需要三次乘法。而乘以 是 级别的。这里每次递归变为原来的 ,从而有
直接实现复杂度为 , 大概是 1.585 左右。然后再考虑预处理 以内的乘法表,那就直接起飞了。This makes multiplication about 5 times faster than naive approach.
显然只处理 256 以内的乘法表不够劲爆,我们考虑处理 65536 以内的乘法表。你可能会很疑惑,处理 65536 以内的乘法表不是去世了吗?下面就由小编带大家来了解吧。
简单来说就是,事实上在 nimber 中也是有原根存在的,从而我们考虑处理出所有 , 就直接 ln[exp[x]]=x
。
考虑原根 ,它使得序列 构成了一组线性基(否则可以证明 并非原根)。从而任意 可以被它们用加法线性表示,实际实现的时候只需要使用 的表示然后递推出它们各自的线性表示即可。
这里放一个 yhx 杯爷找出的高妙原根和它的 序列。这个原根有一个性质是 ,使得它和方法 2 的结合更快了。
xxxxxxxxxx
namespace nimbers {
constexpr u32 n2f[16] = {0x0001u, 0x8ff5u, 0x6cbfu, 0xa5beu, 0x761au, 0x8238u, 0x4f08u, 0x95acu, 0xf340u, 0x1336u, 0x7d5eu, 0x86e7u, 0x3a47u, 0xe796u, 0xb7c3u, 0x0008u},
f2n[16] = {0x0001u, 0x2827u, 0x392bu, 0x8000u, 0x20fdu, 0x4d1du, 0xde4au, 0x0a17u, 0x3464u, 0xe3a9u, 0x6d8du, 0x34bcu, 0xa921u, 0xa173u, 0x0ebcu, 0x0e69u};
inline u32 nimber2field(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= n2f[ctz(x)]; return y;}
inline u32 field2nimber(u32 x) {u32 y = 0; for (; x; x &= x - 1) y ^= f2n[ctz(x)]; return y;}
inline u32 __builtin_double(u32 x) {return x << 1 ^ (x < 0x8000u ? 0 : 0x1681fu);}
...
由于 nimber 是一个有限域,从而一定有
别问我为什么……要解释的话又要写一堆东西了。
于是 。快速幂即可。
你好啊小机器人。你学会数数了吗,还是说你还卡在 0 和 1 上?
这个 OJ 好像爆了,而且疑似是一个校内 OJ?
简要题意:
一张每个连通分量都是完全图的有标号无向图对应一个游戏:记各连通分量的大小为 ,这个游戏是 。对于每个 ,求所有这种大小为 的无向图的和是否先手必胜,如果先手必胜,还要输出:如果只能修改 ,该如何修改才能使先手必败。
先考虑求所有图的和。显然一个连通分量的 EGF 可以写成
从而答案的 EGF 为
停一停。你真的知道你在写什么东西吗?我们必须先保证这个所谓 “EGF” 的卷积仍然是二项卷积。
其中 是实数。说真的, 到底是什么意思?从组合上来讲,它应当表示把 重复加 次。从而我们定义 nimber 上的整数乘 。我们当然期望有 ,但是显然这是不可能的,因为 ,从而 必须同时等于多个数。所以我们只好避开不谈有理数乘,采用某种方式绕过它吧。
不过问题其实不大,我们暴力 Exp
我们知道 ,如果把一个整数看成它的二进制表示描述的集合。从而这就是一个子集卷积。此时已经有一个 Karatsuba 分治乘法做法,但是不够劲爆。我们给出一个劲爆引理:
其中 表示二项/子集卷积。
读者自证不难,只需要注意到任何 nimber 的加法逆元等于自身。
从而,任何常数项为 1 的多项式的二项/子集卷积逆是其自身。于是有
从而,如果忽略乘法的复杂度,我们可以在 的时间内计算 Ln,牛迭即可得到 Exp。
然后考虑怎么修改 ,假设修改为 。则有
于是就做完了。
不知不觉写了这么多?
其他的高科技等初赛考完能借到论文集再说吧。到时候重开一篇文章。