BSGS算法
BabyStepGiantStep
B
a
b
y
S
t
e
p
G
i
a
n
t
S
t
e
p
算法,即大步小步算法,缩写为
BSGS
B
S
G
S
拔山盖世算法
它是用来解决这样一类问题
yx=z(mod p)
y
x
=
z
(
m
o
d
p
)
,给定
y,z,p>=1
y
,
z
,
p
>=
1
求解
x
x
普通的只能用来解决 gcd(y,p)=1 g c d ( y , p ) = 1 的情况
设
x=a∗m+b,m=⌈p‾√⌉,a∈[0,m),b∈[0,m)
x
=
a
∗
m
+
b
,
m
=
⌈
p
⌉
,
a
∈
[
0
,
m
)
,
b
∈
[
0
,
m
)
那么
ya∗m=z∗y−b(mod p)
y
a
∗
m
=
z
∗
y
−
b
(
m
o
d
p
)
怎么求解,为了方便,设
x=a∗m−b
x
=
a
∗
m
−
b
那么
ya∗m=z∗yb(mod p),a∈(0,m+1]
y
a
∗
m
=
z
∗
y
b
(
m
o
d
p
)
,
a
∈
(
0
,
m
+
1
]
直接暴力辣,把右边的
b
b
枚举,算出
z∗yb(mod p)
z
∗
y
b
(
m
o
d
p
)
,哈希存起来
然后左边
a
a
枚举,算出
ya∗m(mod p)
y
a
∗
m
(
m
o
d
p
)
查表就行了
然后不知道为什么要用 exgcd e x g c d ,只会 map m a p …
代码
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
using namespace std;
typedef long long ll;
template <class Int>
IL void Input(RG Int &x){
RG int z = 1; RG char c = getchar(); x = 0;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
x *= z;
}
IL void None(){
puts("Orz, I cannot find x!");
}
int p;
IL int Pow(RG ll x, RG ll y){
RG ll ret = 1;
for(; y; x = x * x % p, y >>= 1)
if(y & 1) ret = ret * x % p;
return ret;
}
map <int, int> pw;
IL void BSGS(RG int x, RG int y){
pw.clear();
if(y == 1){
puts("0");
return;
}
RG int ans = -1, m = sqrt(p) + 1, xx, s = y;
for(RG int i = 0; i < m; ++i){
pw[s] = i;
s = 1LL * s * x % p;
}
xx = Pow(x, m), s = 1;
for(RG int i = 1; i <= m + 1; ++i){
s = 1LL * s * xx % p;
if(pw.count(s)){
ans = i * m - pw[s];
break;
}
}
if(ans < 0) None();
else printf("%d\n", ans);
}
int T, k, y, z;
int main(RG int argc, RG char* argv[]){
for(Input(T), Input(k); T; --T){
Input(y), Input(z), Input(p);
if(k == 1) printf("%d\n", Pow(y, z));
else if(k == 2){
RG int d = (y % p) ? 1 : p;
if(z % d) None();
else printf("%lld\n", 1LL * Pow(y, p - 2) * z % p);
}
else{
if(y % p) BSGS(y % p, z % p);
else None();
}
}
return 0;
}
扩展BSGS
对于 gcd(y,p)≠1 g c d ( y , p ) ≠ 1 怎么办?
我们把它写成 y∗yx−1+k∗p=z,k∈Z y ∗ y x − 1 + k ∗ p = z , k ∈ Z 的形式
根据
exgcd
e
x
g
c
d
的理论
那么如果
y,p
y
,
p
的
gcd
g
c
d
不是
z
z
的约数就不会有解
设
那么
递归到
d=1
d
=
1
设之间的所有的
d
d
的乘积为,递归
c
c
次
令
那么
那么 BSGS B S G S 求解就好了
代码
# include <bits/stdc++.h>
# define RG register
# define IL inline
# define Fill(a, b) memset(a, b, sizeof(a))
# define File(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
using namespace std;
typedef long long ll;
template <class Int>
IL void Input(RG Int &x){
RG int z = 1; RG char c = getchar(); x = 0;
for(; c < '0' || c > '9'; c = getchar()) z = c == '-' ? -1 : 1;
for(; c >= '0' && c <= '9'; c = getchar()) x = (x << 1) + (x << 3) + (c ^ 48);
x *= z;
}
map <int, int> pw;
IL int Gcd(RG int x, RG int y){
return !y ? x : Gcd(y, x % y);
}
IL int Pow(RG ll x, RG ll y, RG int p){
RG ll ret = 1;
for(; y; x = x * x % p, y >>= 1)
if(y & 1) ret = ret * x % p;
return ret;
}
int a, b, p;
IL int EX_BSGS(){
if(b == 1) return 0;
pw.clear();
RG int cnt = 0, t = 1, s, x, m;
for(RG int d = Gcd(a, p); d != 1; d = Gcd(a, p)){
if(b % d) return -1;
++cnt, b /= d, p /= d, t = 1LL * t * a / d % p;
if(b == t) return cnt;
}
s = b, m = sqrt(p) + 1;
for(RG int i = 0; i < m; ++i){
pw[s] = i;
s = 1LL * s * a % p;
}
x = Pow(a, m, p), s = t;
for(RG int i = 1; i <= m; ++i){
s = 1LL * s * x % p;
if(pw.count(s)) return i * m - pw[s] + cnt;
}
return -1;
}
int ans;
int main(RG int argc, RG char* argv[]){
for(Input(a), Input(p), Input(b); a + b + p;){
a %= p, b %= p, ans = EX_BSGS();
if(ans < 0) puts("No Solution");
else printf("%d\n", ans);
Input(a), Input(p), Input(b);
}
return 0;
}