离散对数
zzafanti orz
求 \(\log_a b\bmod N\),\(N\) 是素数。
首先不妨设底数为原根。
BSGS:设定阈值 \(B\),预处理 \(g^0,g^1,\dots,g^{B-1}\) 和 \(g^0,g^B,g^{2B},\dots\) 扔到哈希表里,这样对于 \(Q\) 组询问就做到了 \(O\left(B+\dfrac{NQ}{B}\right)\),平衡一下得到 \(O(\sqrt{NQ})\)。
首先预处理出来 \(1\sim\sqrt N\) 的离散对数。假设要求 \(\log x\),设 \(N=px+q\)(带余除法),那么:
\(p\le \sqrt N\),于是 \(\log p\) 是已知的,所以只需要求出来 \(\log q\),这个直接递归下去求解。和 \(O(1)\) 逆元的处理方式很像,效率也很高。
对于预处理的部分,相当于要做 \(O(\sqrt N)\) 次查询,于是复杂度为 \(O(N^{0.75})\)。但是根据 \(\log(xy) = \log x + \log y\),用类似线性筛的方法,求出来素数处的点值就够了,于是可以优化到 \(O\left(\dfrac{N^{0.75}}{\sqrt{\log N}}\right)\)。
应用:给定 \(a_1,a_2,\dots,a_n\) 和素数 \(P\),求 \(\prod_{i=1}^n i^{a_i}\bmod P\)。
用上面的离散对数可以直接线性筛出来 \(1\sim n\) 的离散对数,预处理离散对数后复杂度线性。
不过还有另一个更巧妙的做法:把每个数 \(i\) 的贡献拆到素数幂上,然后从大到小枚举 \(i\),把 \(i\) 的贡献拆到 \(p_i^w_i\) 和 \(i/p_i^w_i\) 上,最后在素数处计算一下答案就好了,复杂度同样是线性,并且和模数无关。
浙公网安备 33010602011771号