CodeChef November Challenge2019 Winning Ways (3-FWT)
CodeChef November Challenge2019 Winning Ways (3-FWT)
显然每个把每个数换成其因子个数-1,就能转为一个扩展的 \(\text{Nim}\) 游戏
每次操作 \(1,2,\cdots,k\) 堆的 \(\text{Nim}\) 游戏,其判定方法是:
将每个数二进制分解,对于每个二进制位上分别计算1的个数 \(\mod (k+1)\) ,如果均为0则先手必败
对于这道题 \(k=3\) ,我们考虑将其转为二进制之后的形式累成3进制,然后就能进行3进制按位不进位加法,即类异或
然后问题实际上有非常多的部分需要考虑
Part1 如何求因子个数
一个简单的方法是枚举 \([1,\sqrt n]\) 判断是否整除,复杂度过高
对于 \(n=\prod p_i^{c_i}\) ( \(p_i\) 为质数),其因子个数为 \(\prod (c_i+1)\)
由这个式子对于 \(n\) 进行质因数分解,枚举 \([1,\sqrt n]\) 中的质数,复杂度为 \(O(\pi(\sqrt n))=O(\frac{\sqrt n}{\log n})\) ,这个应该够了?
然后是一个常规套路型的分解方法:
先对于 \([1,n^{\frac{1}{3}}]\) 的质数筛 \(n\) ,剩余的部分只有3种情况
\(n\) 被筛成1了
\(n\) 被筛到只剩一个质数,可以用 \(\text{Miller_Rabin}\) 算法快速判断,可以参考
\(n\) 仍然是若干质数的乘积,此时质因子必然 \(>n^{\frac{1}{3}}\) ,因此最多只有两个
那么只需要判断 \(n\) 是否是完全平方数即可
总复杂度为 \(O(w\cdot \log n+\frac{n^{\frac{1}{3}}}{\log n})\) ,其中 \(w\) 为 \(\text{Miller_Rabin}\) 筛选次数
1 | const int N=2e5+10; |
Part2 快速计算答案
\(10^9\) 以内的数,最大因子个数为 \(1334\) ,这个数为 \(931170240\)
转成二进制之后最多包含 \(11\) 位,三进制下最大为 \(3^{11}-1=177146\) ,令这个上界为 \(M\)
一种非常暴力的方法就是直接枚举, \(NM\) 计算每次选择一个数,复杂度为 \(O(NMK)\) ,应该可以通过 \(N\leq 12\) 的数据
一个比较浅显的优化可以用快速幂维护乘法,复杂度为 \(O(M^2\log K)\)
由于是3进制类异或,接下来考虑用 \(\text{3-FWT}\) 优化乘法,可以参考
模数为 \(P=10^9+7\) ,不存在整数 \(3\) 阶单位根,因此要用类似拆系数 \(\text{FFT}\) 方法做
复杂度为 \(O(M\log M\log K)\) ,似乎已经比较小了,但是常数非常大,应该难以通过
1 | int R;// R为上界 |
Further
对于形式幂级数多项式,我们知道 \(K\) 次幂的循环卷积可以直接 \(\text{DFT}\) 一次,每一位快速幂,然后 \(\text{IDFT}\)
同理的,如果你学习了 \(\text{K-FWT}\) 就知道这就是一个按 \(K\) 进制位,每一位分别进行循环卷积,因此也可以用类似的方法做
但是遇到一个非常大的问题就是无法找到模意义下的 \(3\) 阶单位根(指 \(3\not |(P-1)\) )
如果用复平面单位根 \(\omega_n=cos(\frac{2\pi}{n})+sin(\frac{2\pi}{n})\cdot i\) ( \(i=\sqrt {-1})\) ,无法在计算时保证值域精度
这里由于 \(n=3\) 比较特殊,发现 \(\omega_3=cos(\frac{2\pi}{3})+sin(\frac{2\pi}{3})\cdot i=-\frac{1}{2}+\frac{\sqrt 3}{2}\cdot i\)
而 \(3\) 在 \(\mod 10^9+7\) 下存在二次剩余,因此可以用一个模意义下的复数描述复平面单位根
应该是有通行的单位根求法,会根据 \(n\) 不同要用更复杂的高维复数描述,但是我并不会.jpg
总复杂度为 \(O(M(\log M+\log K))\) ,分别为进行 \(\text{3-FWT}\) 以及快速幂的复杂度
Code总览:
1 |
|