https://maspypy.com/o1-mod-inv-mod-pow
记
x≡y(modP) 为
x≡y(P)。
Farey 序列
记
Fn 为
n 阶 Farey 序列,就是所有分母不超过
n 的既约真分数带上
10 和
11 排序组成的序列,如
F5=[10,51,41,31,52,21,53,32,43,54,11]。
引理
对任意
v∈[0,1],n∈Z>0 存在
qp∈Fn 使得
∣v−qp∣≤qn1。符合的
qp 一定是
max(Fn∩[0,v]) 或者
min(Fn∩[v,1])。
证
第一部分,
{x}:=x−⌊x⌋。将
{{iv}:i∈[0,n],i∈Z} 排序,易得定存在
0≤i<j≤n 使得
∣{jv}−{iv}∣≤n1。令
q:=j−i,p:=⌊jv⌋−⌊iv⌋。
∣qv−p∣=∣⌊jv⌋+{jv}−⌊iv⌋−{iv}−p∣≤n1第二部分,不妨设我们找到的
qp<v。如果
(qp,v) 之间还有
Fn 中的
q′p′,那么
v−qp>q′p′−qp≥qq′1≥qn1 从而矛盾。
下面三种算法,都是先找到
∣Px−qp∣≤qn1 的
qp,就有
∣qx−pP∣≤nP,
t:=qxmodP∈[−nP,nP]。
怎么找
qp 呢?因为
Fn 中数两两之差大于
n21,故
⌊qn2p⌋ 互不相同,把所有这些值存起来然后用
⌊Pn2x⌋ 找前驱后继即可。这需要
O(n2) 的时间。
O(P32)−O(1) 逆元
求
x−1modP,先将所有可能的
t 的
t−1 预处理出来(离线
O(1) 逆元),然后
x−1≡qt−1(P)。
O(nP+n2)−O(1),取
n∼P31 即可做到
O(P32)−O(1)。
O(log1/2(P)P3/4)−O(1) 离散对数
令
g 为
P 的原根,
log(x) 表示
g 为底的离散对数,有
log(−1)=2P−1。首先要知道预处理出
[1,m] 中所有数的对数的复杂度为
⎩⎨⎧O(logmPm),O(log1/2(P)P3/4+m),m≤Potherwise
Info
m≤P 时,考虑先对所有范围内质数的离散对数求解。发现一般的 BSGS 的
log(x) 实际上是固定
B 然后求解整数对
(y,z) 使得
y≤BPz<B(gB)y≡xgz(P)由于有
π(m) 次查询,左边要
BP 次哈希表插入,右边要
π(m)⋅B 次哈希表查找,令
B:=π(m)P 即可。
有了所有质数的对数之后,利用
log(pq)≡log(p)+log(q)(P−1) 即可线性筛得出
m 以内所有数的离散对数。
m≥P 时,先求出
[1,n] 以内的离散对数,然后求
log(x) 时,令
P=:kx+r 则
log(x)≡log(−r)−log(k)≡2P−1+log(r)−log(k)(modP−1)递推即可。
由于
n2≤P,预处理
[1,nP] 上的离散对数,那么
[−nP,−1] 的也同时可以求出来。
log(x)≡log(qt)≡log(t)−log(q)(P−1)。于是复杂度为
O(n2+log1/2(P)P3/4+nP)−O(1),取
n∼P31 即为
O(log1/2(P)P3/4)−O(1)。
O(log1/2(P)P3/4)−O(1) 模幂
ab≡gblog(a)(P),再预处理
g 的光速幂即可。
O(log1/2(P)P3/4)−O(1) 二次剩余
设
g 是
P 的一个原根,现在求解方程
x2≡a(modP)。将
a 表示为
gkmodP。如果
k 是偶数那么
g2kmodP 是一个解。否则
a 不是二次剩余。