浅谈BSGS&exBSGS
概(che)论(dan)
BSGS又称拔山盖世算法
Baby Step Giant Step
又称求离散对数
一般用于给出
a
,
b
,
p
a, b, p
a,b,p求
a x ≡ b ( m o d p ) a^x \equiv b \pmod p ax≡b(modp)
算法流程
比较简单,其实就是分块,小块的暴力预处理,然后一块一块跳
借用 psk011102 的图
大概就是这样
先丢个板子题吧:
代码实现很简单:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll p, b, n, mod;
map<ll, ll> mp;
ll qpow(ll x, int y) {
ll ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
int BSGS(int p, int b, int n) {
int m = sqrt(p) + 1; ll t = n; mod = p;
for(int i = 0; i <= m; i ++, t = t * b % mod) mp[t] = i;//先把<=m的丢进map里面
ll tt = qpow(b, m); t = tt;//每次跳m个
if(!tt) return n == 0? 1 : -1;//特判0
int f = 0;
for(int i = 1; i <= m + 1; i ++, t = t * tt % mod) {
int j = mp.find(t) == mp.end()? -1 : mp[t];
if(j >= 0) return i * m - j;//如果找到了就返回
}
return -1;
}
int main() {
scanf("%lld%lld%lld", &p, &b, &n);
int l = BSGS(p, b, n);
if(l == -1) printf("no solution");
else printf("%d ", l);
return 0;
}
是不是很简单!!!
要注意这里必须满足
a
⊥
p
a \perp p
a⊥p
如果不满足呢?
exBSGS
即
a
,
p
a,p
a,p不互质
先设
d
=
g
c
d
(
a
,
p
)
d=gcd(a,p)
d=gcd(a,p)
1、如果
d
∤
b
d∤b
d∤b,只有唯一解
x
=
0
,
b
=
1
x=0,b=1
x=0,b=1
证明:
可以直接把式子写出来
a
x
≡
b
(
m
o
d
p
)
a^x \equiv b \pmod p
ax≡b(modp)
改一下
a
x
−
1
a
+
k
p
≡
b
(
m
o
d
p
)
a^{x-1}a+kp \equiv b \pmod p
ax−1a+kp≡b(modp)
根据裴蜀定理可得
g
c
d
(
a
,
p
)
∣
b
gcd(a,p)|b
gcd(a,p)∣b
2、如果
d
∣
b
d|b
d∣b
先两边除
d
d
d
a
x
−
1
×
a
d
≡
b
d
(
m
o
d
p
d
)
a^{x-1} \times\frac{a}{d} \equiv \frac{b}{d} \pmod {\frac{p}{d}}
ax−1×da≡db(moddp)
除过去
a
x
−
1
≡
b
d
×
(
a
d
)
−
1
(
m
o
d
p
d
)
a^{x-1} \equiv \frac{b}{d} \times (\frac{a}{d})^{-1}\pmod {\frac{p}{d}}
ax−1≡db×(da)−1(moddp)
板子
code:
#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll exgcd(ll &x, ll &y, ll a, ll b) {
if(!b) {x = 1, y = 0; return a;};
ll d = exgcd(y, x, b, a % b); y -= x * (a / b);
return d;
}
ll qpow(ll x, ll y, ll mod) {
ll ret = 1;
for(; y; y >>= 1, x = x * x % mod) if(y & 1) ret = ret * x % mod;
return ret;
}
ll getinv(ll a, ll b) {
ll x, y;
exgcd(x, y, a, b);
return (x % b + b) % b;
}
map<ll, ll> mp;
ll BSGS(ll a, ll b, ll mod) {
mp.clear();
int m = sqrt(mod) + 1;
ll t = b % mod;
for(int i = 0; i <= m; t = t * a % mod, i ++) mp[t] = i;
a = qpow(a, m, mod); t = a;
if(!t) return b == 0? 1 : -1;
for(int i = 1; i <= m + 1; i ++, t = t * a % mod) {
int j = mp.find(t) == mp.end()? -1 : mp[t];
if(j != -1) return 1ll * i * m - j;
}
return - 1;
}
ll exBSGS(ll a, ll b, ll p) {
if(b == 1) return 0;
ll d = 0, k = 0;
while((d = __gcd(a, p)) != 1) {
if(b % d) return - 1;
++ k; p /= d, b = (b / d) * getinv((a / d), p) % p;
if(b == a) return k;
}
ll ans = BSGS(a, b, p);
return ans == -1? -1 : ans + k;
}
ll a, b, p;
int main() {
while(1) {
scanf("%lld%lld%lld", &a, &p, &b);
if(!(a || b || p)) return 0;
ll ans = exBSGS(a, b, p);
if(ans != -1) printf("%lld\n", ans);
else printf("No Solution\n");
}
return 0;
}