首先单次查询离散对数可以考虑 BSGS,将 g0,gB,g2B,g3B,,gP/B×Bg^0, g^B, g^{2B}, g^{3B}, \dots, g^{P / B \times B} 插入哈希表,然后枚举 i=0,1,2,,B1i = 0, 1, 2, \dots, B - 1 在哈希表中查询 y×giy \times g^{-i} 即可。

现在我们考虑求出 log1,log2,,logn\log 1, \log 2, \dots, \log n 怎么做。显然这个离散对数也满足 logab=loga+logb\log ab = \log a + \log b,所以我们只需要求出质数位置上的离散对数即可。

那么直接套用 BSGS 的做法,预处理时间复杂度为 O(P/B)\mathcal{O}(P / B),所有查询时间复杂度为 O(nBlnn)\mathcal{O}(\frac{nB}{\ln n})Plnn=nB2P \ln n = n B^2,平衡得到 B=PlnnnB = \sqrt{\frac{P \ln n}n}

考虑怎么预处理一些东西来快速回答询问。假设我们预处理了 P+1\sqrt P + 1 以内的 log\log 值,现在要求 logy\log y,那么若 yP+1y \le \sqrt P + 1 就直接返回,否则令 k,rk, r 分别为 PP 除以 yy 的商和余数,考虑 rryry - r 之中一定有一个不大于 yy 的一半,如果能够规约到对应的子问题上,就可以做到单次查询 O(logP)\mathcal{O}(\log P)。接下来有对应的两种方式:

  1. 将模数 PP 表示为 ky+rky + r,变形得到 y=Prk=rky = \frac{P - r}k = \frac{-r}k,那么 logy=log(r)logk=log(1)+logrlogk\log y = \log(-r) - \log k = \log(-1) + \log r - \log k
  2. 将模数 PP 表示为 (k+1)y(yr)(k + 1)y - (y - r),变形得到 y=P+yrk+1=yrk+1y = \frac{P + y - r}{k + 1} = \frac{y - r}{k + 1},那么 logy=log(yr)log(k+1)\log y = \log(y - r) - \log(k + 1)

通过 y>P+1y > \sqrt P + 1 可以得出 kPk \le \sqrt P,那么 logk,log(k+1)\log k, \log (k + 1) 可以直接查表,选择对应的子问题递归下去即可。

回到前面预处理的部分,将 n=Pn = \sqrt P 代入,得到 B=P1/4ln1/2PB = P^{1/4} \ln^{1/2} P。则预处理部分时间复杂度为 O(P3/4ln1/2P)\mathcal{O}\left(\frac{P^{3/4}}{\ln^{1/2} P}\right),可以通过。

代码