离散对数随笔

本文介绍了欧拉定理的阶的概念,以及如何通过Pollard-Rho分解和原根性质快速计算阶。此外,文章详细讲解了BSGS算法及其扩展版本用于解决离散对数问题,指出其时间复杂度和实现技巧。
摘要由CSDN通过智能技术生成

我们都知道欧拉定理,对于 a ∈ Z a\in \Z aZ m ∈ N ∗ m\in\N^* mN,且 ( a , m ) = 1 (a,m)=1 (a,m)=1,则有 a φ ( m ) ≡ 1 ( m o d m ) a^{\varphi(m)}\equiv1\pmod m aφ(m)1(modm),其中 ( a , m ) (a,m) (a,m) gcd ⁡ ( a , m ) \gcd(a,m) gcd(a,m) 的简写。即每经过 φ ( m ) \varphi(m) φ(m) 就绕了一圈。

但事实上可能存在更小的 n ∣ φ ( m ) n|\varphi(m) nφ(m),使得 a n ≡ 1 ( m o d m ) a^n\equiv1\pmod m an1(modm) 成立,最小的使得这个式子成立的 n n n 称为 a a a m m m 的阶,记作 ord m ( a ) \text{ord}_m(a) ordm(a) 或者 δ m ( a ) \delta_m(a) δm(a)

它有一些性质:

  • δ m ( a ) ∣ φ ( m ) \delta_m(a)\mid\varphi(m) δm(a)φ(m)
  • δ m ( a b ) = δ m ( a ) δ m ( b ) ↔ ( δ m ( a ) , δ m ( b ) ) = 1 \delta_m(ab)=\delta_m(a)\delta_m(b)\leftrightarrow(\delta_m(a),\delta_m(b))=1 δm(ab)=δm(a)δm(b)(δm(a),δm(b))=1
  • δ m ( a k ) = δ m ( a ) ( δ m ( a ) , k ) \delta_m(a^k)=\frac{\delta_m(a)}{(\delta_m(a),k)} δm(ak)=(δm(a),k)δm(a)

这里忽略证明,感兴趣的话可以看 这里

怎么计算 δ m ( a ) \delta_m(a) δm(a)? 由于 a φ ( m ) ≡ 1 ( m o d m ) a^{\varphi(m)}\equiv1\pmod m aφ(m)1(modm) δ m ( a ) ∣ φ ( m ) \delta_m(a)|\varphi(m) δm(a)φ(m),所以可以记 t = φ ( m ) t=\varphi(m) t=φ(m),然后每次尝试把 t t t 除以 φ ( m ) \varphi(m) φ(m) 的质因数,配合 Pollard-Rho 分解质因数是 O ( m 1 4 + log ⁡ m ) O(m^{\frac{1}{4}}+\log m) O(m41+logm) 的。

原根

我去,原

对于 m ∈ Z m\in\Z mZ,若有 ( g , m ) = 1 (g,m)=1 (g,m)=1,满足 δ m ( g ) = φ ( m ) \delta_m(g)=\varphi(m) δm(g)=φ(m),则称 g g g m m m 的原根。

它也有一些性质:

  • 一个正整数 m m m 存在原根,当且仅当它可以表示成 2 , 4 , p k , 2 p k 2,4,p^k,2p^k 2,4,pk,2pk 中的一个。
  • g g g m m m 的原根,则有 g φ ( m ) p ≢ 1 ( m o d m ) g^{\frac{\varphi(m)}{p}}\not\equiv1\pmod m gpφ(m)1(modm),其中 p p p m m m 任意一个质因数。
  • m m m 最小原根的大小为 O ( m 0.25 ) O(m^{0.25}) O(m0.25)
  • g g g m m m 的原根,且对于 k ∈ N ∗ k\in \N^* kN,有 ( k , φ ( m ) ) = 1 (k,\varphi(m))=1 (k,φ(m))=1 ,则 g k g^k gk 也是 m m m 的一个原根。
  • m m m 若存在原根,则它的原根个数是 O ( φ ( φ ( m ) ) ) O(\varphi(\varphi(m))) O(φ(φ(m)))

第一点让我们知道一个数有没有原根( O ( m log ⁡ m ) O(m\log m) O(mlogm))预处理, O ( 1 ) O(1) O(1) 判断)。

第二点就是判定一个数是不是 m m m 原根的方法(依次选取 p p p 并判断)复杂度 O ( log ⁡ m ) O(\log m) O(logm)

第三点保证我们可以在 O ( m 0.25 log ⁡ m ) O(m^{0.25}\log m) O(m0.25logm) 时间内找到最小原根(暴力枚举)。

第四点和第五点让我们可以在 O ( φ ( m ) log ⁡ m ) O(\varphi(m)\log m) O(φ(m)logm) 时间内找到其他原根。

于是就可以在 O ( m log ⁡ m ) O(m\log m) O(mlogm) 时间内找出 m m m 的所有原根。

板题:P6091 【模板】原根

离散对数

对于一个正整数 m m m 和其原根 g g g(假设其存在),满足 g x ≡ b ( m o d m ) g^x\equiv b\pmod m gxb(modm),其中 0 ≤ x < φ ( m ) 0\le x<\varphi(m) 0x<φ(m),则称 x x x b b b g g g 为底模 m m m 的指数,记作 ind g b \text{ind}_g b indgb。显然这样的 x x x 是唯一的。

它同样有一些性质:

对于 ( a , m ) = 1 (a,m)=1 (a,m)=1 ( b , m ) = 1 (b,m)=1 (b,m)=1,有

  • ind g a b ≡ ind g a + ind g b ( m o d φ ( m ) ) \text{ind}_gab\equiv\text{ind}_ga+\text{ind}_gb\pmod{\varphi(m)} indgabindga+indgb(modφ(m))
  • ind g a k = k   ind g a ( m o d φ ( m ) ) \text{ind}_ga^k=k\,\text{ind}_ga\pmod{\varphi(m)} indgak=kindga(modφ(m))
  • r r r 也为 m m m 的原根,则 ind g a = ind r a × ind g r ( m o d φ ( m ) ) \text{ind}_ga=\text{ind}_ra\times\text{ind}_gr\pmod{\varphi(m)} indga=indra×indgr(modφ(m))
  • a ≡ b ( m o d m ) a\equiv b\pmod m ab(modm),则 ind g a = ind g b \text{ind}_ga=\text{ind}_gb indga=indgb

那么如何求解离散对数呢?

BSGS 算法

BSGS 全称 Baby-step Gaint-step,中文大步小步算法。对于正整数 a a a b b b m m m,它可以用来求解
a x ≡ b ( m o d m ) a^x\equiv b\pmod m axb(modm)
其中 ( a , m ) = 1 (a,m)=1 (a,m)=1 m m m 不一定为质数。

怎么做呢?令 x = A t − B x=At-B x=AtB,其中 1 ≤ A ≤ ⌈ φ ( m ) t ⌉ 1\le A\le \left\lceil\frac{\varphi(m)}{t}\right\rceil 1Atφ(m) 1 ≤ B ≤ t 1\le B\le t 1Bt,这样 A t − B At-B AtB 能取遍 0 0 0 φ ( m ) − 1 \varphi(m)-1 φ(m)1

于是有
a A t ≡ a B b ( m o d m ) a^{At}\equiv a^{B}b\pmod m aAtaBb(modm)

于是可以枚举所有 B B B,把 a B b   m o d   m a^Bb\bmod m aBbmodm 可能的取值记下来(用哈希表或平衡树),再从小到大枚举 A A A,判断是否有和 a A t a^{At} aAt 同余的 a B b a^Bb aBb,若有,则答案为 A t − B At-B AtB。如果全部枚举完都没有符合条件的,就说明无解。

显然 t t t ⌊ m ⌋ + 1 \left\lfloor \sqrt m\right\rfloor+1 m +1 时间复杂度最小。

代码:

map<ll, int> mp;
ll BSGS(ll a, ll b, ll p) {
    mp.clear(), a %= p, b %= p;
    ll cur = 1, t = sqrt(p) + 1;
    lp(i, 1, t) (cur *= a) %= p, mp[b * cur % p] = i;	// 枚举 A
    ll now = cur;
    lp(i, 1, t) {	// 枚举 B
        if(mp.count(now)) return i * t - mp[now];	// 找到了最小的答案
        (now *= cur) %= p;
    }
    return -INF;	// 无解
}

exBSGS

再看这个式子:
a x ≡ b ( m o d m ) a^x\equiv b\pmod m axb(modm)
( a , m ) = 1 (a,m)=1 (a,m)=1 不一定成立,就需要用到 exBSGS。

注意到这个式子可以写成
a a x − 1 + m k = b aa^{x-1}+mk=b aax1+mk=b
由斐蜀定理,其有解的充要条件是 b ∣ ( a , m ) b\mid(a,m) b(a,m),否则无解直接返回,两边同除以 d = ( a , m ) d=(a,m) d=(a,m),得
a d a x − 1 + m d k = b d \frac{a}{d}a^{x-1}+\frac{m}{d}k=\frac{b}{d} daax1+dmk=db

a d a x − 1 ≡ b d ( m o d m d ) \frac{a}{d}a^{x-1}\equiv\frac{b}{d}\pmod{\frac{m}{d}} daax1db(moddm)
此时若 ( a , m d ) = 1 (a,\frac{m}{d})=1 (a,dm)=1,就能用 BSGS 求解,只不过多了个 a d \frac{a}{d} da 系数,稍微改下 BSGS 就行。否则继续递归下去,进行 k k k 次后变成
a k D a x − k ≡ b D ( m o d m D ) \frac{a^k}{D}a^{x-k}\equiv\frac{b}{D}\pmod{\frac{m}{D}} DakaxkDb(modDm)
其中 D = ∏ i = 1 k d i D=\prod_{i=1}^k d_i D=i=1kdi

那么这样的过程最多进行 max ⁡ { max ⁡ ( c i , c i ′ ) min ⁡ ( c i , c i ′ ) } = O ( log ⁡ m ) \max\{\frac{\max(c_i,c_i')}{\min(c_i,c_i')}\}=O(\log m) max{min(ci,ci)max(ci,ci)}=O(logm) 次,其中 c i c_i ci a a a 的质因数 p i p_i pi 的幂次, c i ′ c_i' ci m m m 的质因数 p i p_i pi 的幂次。于是总时间复杂度为 O ( m polylog ) O(\sqrt m \text{polylog}) O(m polylog),若使用哈希就只有一个 log,使用 map 有两个 log。

需要注意若 a k a^k ak m m m b b b(没有除以 d d d 的),就直接返回 k k k

实现上,使用非递归实现,速度较快。

代码:

map<ll, int> mp;
ll BSGS(ll a, ll b, ll p, ll k = 1) {
    mp.clear(), a %= p, b %= p;
    ll cur = 1, t = sqrt(p) + 1;
    lp(i, 1, t) (cur *= a) %= p, mp[b * cur % p] = i;
    ll now = cur * k % p;	// 多乘了个系数
    lp(i, 1, t) {
        if(mp.count(now)) return i * t - mp[now];
        (now *= cur) %= p;
    }
    return -INF;	// 不能返回 -1,因为还加了 i + 1
}

ll exBSGS(ll a, ll b, ll m, ll k = 1) {
    ll A = a %= m, B = b %= m, M = m, cur = 1;
    for(int i = 0; ; ++i) {
        if(cur == B) return i;		// a ^ k % m = b 的情况
        (cur *= A) %= M; ll d = __gcd(a, m);
        if(b % d) return -INF;		// 判无解
        if(d == 1) return BSGS(a, b, m, k * a % m) + i + 1;
        b /= d, m /= d, k = k * a / d % m;
    }
}

板题:【模板】扩展 BSGS/exBSGS

  • 17
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值