地狱人

· · 算法·理论

View it on my blog :)

求解 g^x\equiv a\pmod P,即 \operatorname{ind}_ga\equiv x\pmod{(P-1)}。要求 P-1 较 smooth。

考虑对模数动手。首先我们要明确离散对数在其他模数下的定义。假设模数 m\mid(P-1)\operatorname{ind}_ga\equiv x_0\pmod m。带入原始的指数方程:

g^{km+x_0}\equiv a\pmod P

为分离出 x_0,我们要消灭掉指数上的 m。由 Fermat 小定理,有 g^{P-1}\equiv 1\pmod P,且我们有 m\mid(P-1),故可以左右同取 \frac{P-1}{m} 次幂:

\left(g^{km+x_0}\right)^{\frac{P-1}{m}}\equiv g^{k(P-1)}\cdot g^{\frac{(P-1)x_0}m}\equiv \left(g^{\frac{P-1}{m}}\right)^{x_0}\equiv a^{\frac{P-1}m}\pmod P

如果令 G=g^{\frac{P-1}m},A=a^{\frac{P-1}m},那么我们就得到 G^{x_0}\equiv A\pmod P 的形式。

这个过程在对数意义下也很直观,因为我们可以将整个同余式乘上 \frac{P-1}{m}

\frac{(P-1)x_0}{m}\equiv \frac{P-1}m\operatorname{ind}_ga\equiv \operatorname{ind}_g a^{\frac{P-1}m}\pmod{(P-1)}

Pohlig-Hellman 算法基于以下观察:若已知 x 满足 \operatorname{ind}_g a\equiv x\pmod {p},那么我们容易求解 \operatorname{ind}_ga\equiv x'\pmod {pq}。设 x'=kp+x(0\le k<q),还原成指数形式有:

a^{\frac{P-1}{pq}}\equiv \left(g^{kp+x}\right)^{\frac{P-1}{pq}}\equiv\left(g^{\frac{P-1}{q}}\right)^k\cdot g^{\frac{(P-1)x}{pq}}\pmod P

由这个式子,我们可以用 BSGS 解出 k,进而得出 x'。单次递推的复杂度为 O(\sqrt q)

利用这个结论,比较自然的想法是:选取一个模数路径 m_1\mid m_2\mid \dots\mid m_n=P-1,求出 \operatorname{ind}_g a\equiv x_1\pmod {m_1},然后依次递推出答案。这当然是可行的,不过稍显复杂。

我们知道求解各种模意义下的方程,经常用到 CRT。在这个算法下,CRT 其实也可以看作是模数 p\to pq 的一次递推,即先求解模 pq 的 case,然后合并。在底数固定的情况下,CRT 合并的开销极低,那么我们大可以将所有 p,q 互质的情况都用 CRT。于是我们只需要考虑用刚才的递推求解 \operatorname{ind}_ga\equiv x\pmod {p^\alpha}

为了减小递推的开销,Pohlig-Hellman 算法直接令模数路径中相邻项之间的商为素因子 p,即令模数按照 p\to p^2\to\dots 的路径递推。那么以上的 P-H 递推可以形象地解释为 p 进制数位的递推:设 xp 进制表示为 x=x_0+x_1p+\dots+x_{\alpha-1}p^{\alpha - 1}。这个对数方程左右同乘上一个 p^j,就抹去了 xp 进制下的较高位:

p^j\operatorname{ind}_ga\equiv \sum_{i<\alpha}x_ip^{i+j}\pmod {p^\alpha}

于是等式右边 i+j\ge\alpha 的项就全部被抹去,得到一个关于 x_0,x_1,\dots,x_{\alpha-j-1} 的等式。为了能够计算,化为指数形式:

A^{p^j}\equiv G^{\sum_{i+j<\alpha}x_ip^{i+j}}\equiv \prod_{i+j<\alpha}G^{x_ip^{i+j}}\pmod P

此时我们可以用 BSGS 算出 x_{\alpha-j-1}。实际实现中,由于 p 较小,有时也会直接枚举 x_{\alpha-j-1} 并验证来求解,以避免 BSGS 较大的常数。解决模 p^\alpha 的单个 case 的复杂度为 O(\sqrt p\alpha),总复杂度为 O(\sum (\sqrt{p_i}\alpha_i+\log P))\approx O((\sqrt{\max p}+\omega(P-1))\log P)

回顾 BSGS,我们是对指数做了一个根号分块。那么在 P-H 中,我们通过变换模数,将指数分为了 \alpha=O(\log P) 块求解,并保证这个分块有易于求解的性质。

更进一步地,模数路径中相邻项之商可以灵活选取。对较大的 \alpha,可以令模数按照 p^{\beta}\to p^{2\beta}\to\dots 的路径递推,即将指数看作 p^\beta 进制数。算法过程与之前类似,此时单个 case 的复杂度为 O(p^{\beta/2}\cdot\frac\alpha\beta)

接下来考虑多次询问的情况下,如何预处理以优化单次询问。

事实上后两条优化都脱胎于模数路径的选取。原则很简单:合并互质模数时,CRT 优于 P-H 递推;视具体情况,平衡预处理和递推开销。