BSGS、exBSGS

BSGS (Baby Step Giant Step) : \text{BSGS (Baby Step Giant Step)}: BSGS (Baby Step Giant Step):

给定正整数 a , b , p , a ⊥ p a,b,p,a \perp p a,b,p,ap ,求满足

a x ≡ b (  mod  p ) a^{x} \equiv b(\text{ mod } p) axb( mod p)

最小非负整数 x x x

首先由欧拉定理的推论有:

a x ≡ a x  mod  φ ( p ) (  mod  p ) a^x\equiv a^{x\text{ mod }\varphi (p)}(\text{ mod }p) axax mod φ(p)( mod p)

所以 a x a^x ax 在模 p p p 意义下的最小循环节为 φ ( p ) \varphi(p) φ(p) ,那么只需要考虑 x ∈ [ 0 , φ ( p ) − 1 ] x \in [0,\varphi(p)-1] x[0,φ(p)1] 即可,为了简便避免算欧拉函数,我们对欧拉函数进行放缩 φ ( p ) ≤ p + 1 \varphi(p) \le p + 1 φ(p)p+1,那就是枚举 x ∈ [ 0 , p ] x \in [0,p] x[0,p]。那么我们对暴力枚举的算法做一个优化:令 x = k t − y x =kt-y x=kty , k = ⌊ p ⌋ + 1 ,k=\lfloor \sqrt{p} \rfloor +1 ,k=p +1,则原式为

a k t ≡ b a y (  mod  p ) a^{kt}\equiv ba^{y} (\text{ mod }p) aktbay( mod p)

y y y 的范围是 [ 0 , k − 1 ] [0,k-1] [0,k1] ,所以可以枚举每个 y y y ,预处理右边的值,插入到一个哈希表中,再枚举左边的 t ∈ [ 1 , k ] t\in[1,k] t[1,k] 如果从哈希表找到值,那么就是答案,特判 t = 0 t=0 t=0 的情况,时间复杂度 O ( p ) O(\sqrt{p}) O(p )

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int a, b, p;
int bsgs(int a, int b, int p) {
    if (1 % p == b % p) return 0;
    int k = sqrt(p) + 1;
    unordered_map<int, int> mp;
    for (int i = 0, j = b % p; i < k; i ++) {
        mp[j] = i;
        j = j * a % p;
    }
    int ak = 1;
    for (int i = 0; i < k; i ++) ak = ak * a % p;
    for (int i = 1, j = ak; i <= k; i ++) {
        if (mp.count(j)) return i * k - mp[j];
        j = j * ak % p;
    }
    return -1;
}
signed main() {
    while (cin >> a >> p >> b, a || b || p) {
        int res = bsgs(a, b, p);
        if (res == -1) {
            cout << "No Solution" << endl;
        } else {
            cout << res << endl;
        }
    }
}

exBSGS : \text{exBSGS}: exBSGS:

给定正整数 a , b , p a,b,p a,b,p a , p a,p a,p 不一定互质,求满足

a x ≡ b (  mod  p ) a^{x} \equiv b(\text{ mod } p) axb( mod p)

最小非负整数 x x x

分情况来看,如果 x = 0 x=0 x=0 时,满足 1 ≡ b (  mod  p ) 1 \equiv b(\text{ mod } p) 1b( mod p),答案就是 0 0 0

如果 gcd ⁡ ( a , p ) = 1 \gcd(a,p)=1 gcd(a,p)=1,那么就直接用朴素 BSGS \text{BSGS} BSGS 算法

如果 gcd ⁡ ( a , p ) > 1 \gcd(a,p) > 1 gcd(a,p)>1,由裴蜀定理得

a x + k p = b a^x+kp = b ax+kp=b

gcd ⁡ ( a , p ) = d \gcd(a,p)=d gcd(a,p)=d,如果 d ∤ p d\nmid p dp 那么无解,否则,等式两边同除 d d d

a d a x − 1 + k p d = b d \frac{a}{d}a^{x-1}+k\frac{p}{d} = \frac{b}{d} daax1+kdp=db

等价于同余方程:

a d a x − 1 ≡ b d (  mod  p d ) \frac{a}{d}a^{x-1} \equiv\frac{b}{d} (\text{ mod }\frac{p}{d}) daax1db( mod dp)

由于 gcd ⁡ ( a d , p d ) = 1 \gcd(\frac{a}{d},\frac{p}{d})=1 gcd(da,dp)=1 ,所以把 a d \frac{a}{d} da 移到等式右边,就是乘 a d \frac{a}{d} da 的逆元

a x − 1 ≡ b d ( a d ) − 1 (  mod  p d ) a^{x-1} \equiv\frac{b}{d} (\frac{a}{d})^{-1}(\text{ mod }\frac{p}{d}) ax1db(da)1( mod dp)

用新变量替换:

( a ′ ) x ≡ b ′ (  mod  p ′ ) (a')^{x} \equiv b'(\text{ mod } p') (a)xb( mod p)

由于 x ≥ 1 x \ge 1 x1,这样就可以递归地用 BSGS \text{BSGS} BSGS 求解了,新的解就为 x + 1 x+1 x+1,逆元可以用扩展欧几里得算法求解。

代码:

#include <bits/stdc++.h>
#define int long long
using namespace std;
int a, b, p;
int exgcd(int a, int b, int& x, int& y) {
    if (!b) {
        x = 1, y = 0;
        return a;
    }
    int d = exgcd(b, a % b, y, x);
    y -= a / b * x;
    return d;
}
int bsgs(int a, int b, int p) {
    if (1 % p == b % p) return 0;
    int k = sqrt(p) + 1;
    unordered_map<int, int> mp;
    for (int i = 0, j = b % p; i < k; i ++) {
        mp[j] = i;
        j = j * a % p;
    }
    int ak = 1;
    for (int i = 0; i < k; i ++) ak = ak * a % p;
    for (int i = 1, j = ak; i <= k; i ++) {
        if (mp.count(j)) return i * k - mp[j];
        j = j * ak % p;
    }
    return -1;
}
int exbsgs(int a, int b, int p) {
    b = (b % p + p) % p;
    if (1 % p == b % p) return 0;
    int x, y;
    int d = exgcd(a, p, x, y);
    if (d > 1) {
        if (b % d) return -2e9;
        exgcd(a / d, p / d, x, y);
        return exbsgs(a, b / d * x % (p / d), p / d) + 1;
    }
    return bsgs(a, b, p);
}
signed main() {
    while (cin >> a >> p >> b, a || b || p) {
        int res = exbsgs(a, b, p);
        if (res < 0) {
            cout << "No Solution" << endl;
        } else {
            cout << res << endl;
        }
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值