BSGS(baby step giant step)法是用于求解给出 a , b , p a,b,p a,b,p,求最小的 x x x使 a x ≡ b ( m o d p ) a^x≡b(mod\ p) ax≡b(mod p)
设
m
=
c
e
i
l
(
s
q
r
t
(
m
)
)
m=ceil(sqrt(m))
m=ceil(sqrt(m)),
c
e
i
l
ceil
ceil是
C
+
+
C++
C++中向上取整的符号,那么我们把
x
x
x写成
i
m
−
j
im-j
im−j,相当于
a
i
m
−
j
≡
b
(
m
o
d
p
)
a^{im-j}≡b(mod\ p)
aim−j≡b(mod p)
移项得
a
i
m
≡
b
∗
a
j
(
m
o
d
p
)
a^{im}≡b*a^{j}(mod\ p)
aim≡b∗aj(mod p)
于是我们开一个
m
a
p
map
map,枚举
j
=
1
,
2
…
…
m
j=1,2……m
j=1,2……m,将所有的
b
∗
a
j
b*a^{j}
b∗aj存入
m
a
p
map
map中
然后枚举
i
=
1
,
2
,
…
…
m
i=1,2,……m
i=1,2,……m,并算出所有的
a
i
m
a^{im}
aim,如果这个值在
m
a
p
map
map中出现过,那么那么
i
m
−
m
p
[
a
i
m
]
im-mp[a^{im}]
im−mp[aim]就是答案。(
m
p
mp
mp就是我们记录的
m
a
p
map
map)
那么为什么只计算到
m
=
c
e
i
l
(
s
q
r
t
(
q
)
)
m=ceil(sqrt(q))
m=ceil(sqrt(q)) 就可以确定答案呢?
因为
x
=
i
∗
m
−
j
x = i*m-j
x=i∗m−j , 所以
x
x
x 的最大值不会超过
p
p
p
a
(
k
m
o
d
p
−
1
)
=
a
k
(
m
o
d
p
)
a(k\ mod\ p-1) = ak (mod\ p)
a(k mod p−1)=ak(mod p) 证明这个公式,(需要用到费马小定理)
k
m
o
d
p
−
1
k\ mod\ p-1
k mod p−1 就是
k
−
m
(
p
−
1
)
k-m(p-1)
k−m(p−1) ,原式就变成了
a
k
−
m
(
p
−
1
)
≡
a
k
(
m
o
d
p
)
ak-m(p-1) ≡ ak (mod\ p)
ak−m(p−1)≡ak(mod p)
再变一步
a
k
/
a
m
(
p
−
1
)
≡
a
k
(
m
o
d
p
)
ak / am(p-1) ≡ ak (mod\ p)
ak/am(p−1)≡ak(mod p)
这时让
a
m
(
p
−
1
)
≡
1
(
m
o
d
p
)
am(p-1) ≡ 1 (mod\ p)
am(p−1)≡1(mod p) 就行了。
由费马小定理知: 当
p
p
p为质数且
(
a
,
p
)
=
1
(a,p) = 1
(a,p)=1 时
a
p
−
1
≡
1
(
m
o
d
p
)
ap-1 ≡ 1 (mod\ p)
ap−1≡1(mod p)
所以推出
p
p
p 为质数 且
(
a
,
p
)
=
1
(a,p)=1
(a,p)=1 这个条件, 所以
a
(
k
m
o
d
p
−
1
)
≡
a
k
(
m
o
d
p
)
a(k\ mod\ p-1) ≡ a k (mod\ p)
a(k mod p−1)≡ak(mod p)
所以:如果枚举
x
x
x 的话枚举到
p
p
p 即可。
所以使
i
m
−
j
<
=
p
im−j<=p
im−j<=p , 即
m
=
⌈
p
⌉
m=⌈\sqrt p⌉
m=⌈p⌉ ,
i
,
j
i,j
i,j 最大值也为
m
m
m。
void BSGS(ll x,ll y,ll p){
f.clear();if(f[0])puts("YES");
ll now=y%p,m=ceil(sqrt(p));
if(x%p==0){
puts("Orz, I cannot find x!");return;
}
f[now]=0;
for(ll i=1;i<=m;i++){
now=now*x%p;f[now]=i;
}
ll t=pows(x,m,p);now=1;
for(ll i=1;i<=m;i++){
now=now*t%p;
if(f[now]){
printf("%lld\n",(i*m%p-f[now]+p)%p);return;
}
}
puts("Orz, I cannot find x!");
}