翻译:
bsgs:
baby steps,giant steps
bsgs:
解决以下问题:
有三个整数a,b,p,其中p是质数。
求最小的自然数x,使 a x = b ( m o d p ) a^x=b(mod~p) ax=b(mod p)。
根据费马小定理, a p − 1 = 1 ( m o d p ) a^{p-1}=1(mod~p) ap−1=1(mod p),所以只用考虑x=0~p-1
设 m = p m=\sqrt p m=p,则x可以表示成 i ∗ m + j ( 0 < = i , j < m ) i*m+j(0<=i,j<m) i∗m+j(0<=i,j<m)
a
x
=
b
(
m
o
d
p
)
a^{x}=b(mod~p)
ax=b(mod p)
a
i
∗
m
+
j
=
b
(
m
o
d
p
)
a^{i*m+j}=b(mod~p)
ai∗m+j=b(mod p)
b
∗
a
−
j
=
a
i
∗
m
(
m
o
d
p
)
b*a^{-j}=a^{i*m}(mod ~p)
b∗a−j=ai∗m(mod p)
于是容易想到枚举 j j j,用个hash表存一下 b ∗ a − j b*a^{-j} b∗a−j
接着枚举 i i i,判断hash表里有没有 a i ∗ m a^{i*m} ai∗m就行了。
补充2019.3.7
我们发现求逆元的话在p是质数的情况下还不算麻烦,但是对于exbsgs的话写一个exgcd显然是不划算的。
那么我们可以这么做:
设
m
=
⌈
n
⌉
m=\lceil \sqrt n~\rceil
m=⌈n ⌉
a
x
=
b
a^x=b
ax=b可以写成
a
x
∗
m
−
y
=
b
(
x
,
y
<
=
m
)
a^{x*m-y}=b(x,y<=m)
ax∗m−y=b(x,y<=m)
即
a
x
∗
m
=
a
y
∗
b
a^{x*m}=a^y*b
ax∗m=ay∗b,这样就不用逆元了。
裸题:
【SDOI2011】计算器
Code不放了,与exbsgs类似。
exbsgs:
p不是质数。
a x = b ( m o d p ) a^{x}=b(mod ~p) ax=b(mod p)
设 d = g c d ( a , p ) d=gcd(a, p) d=gcd(a,p)
此时如果b不是d的倍数且b≠1,无解,如果b=1,x=0。
可以改写成:
a
x
−
1
∗
a
d
=
b
d
(
m
o
d
p
d
)
a^{x-1}*{a \over d}={b \over d}(mod ~{p \over d})
ax−1∗da=db(mod dp)
此时a可能与
p
d
{p \over d}
dp还不互质,那就一直取gcd,设取了k次,则最后式子是:
a
x
−
k
∗
a
k
∏
d
i
=
b
∏
d
i
(
m
o
d
p
∏
d
i
)
a^{x-k}*{a^k\over \prod d_i}={b \over\prod d_i }(mod~{p \over \prod d_i})
ax−k∗∏diak=∏dib(mod ∏dip)
此时互质了,直接套用bsgs,答案加个k就行了。
但是要注意一下x < < <k的情况,这个在之前的试除就可以判掉。
Code(【SDOI2011】计算器):
裸题:
SPOJ MOD
Code:
#include<cstdio>
#include<cmath>
#include<map>
#define ll long long
#define fo(i, x, y) for(ll i = x; i <= y; i ++)
using namespace std;
ll a, b, p;
ll ksm(ll x, ll y, const ll mo) {
ll s = 1;
for(; y; y /= 2, x = x * x % mo)
if(y & 1) s = s * x % mo;
return s;
}
ll gcd(ll x ,ll y) {
return !y ? x : gcd(y, x % y);
}
map<ll, ll> h;
ll exbsgs(ll a, ll b, ll p) {
if(b == 1) return 0;
ll k = 0, d = 1, t;
while((t = gcd(a, p)) != 1) {
if(b % t) return -1;
k ++, b /= t, p /= t, d = d * (a / t) % p;
if(b == d) return k;
}
h.clear();
ll m = sqrt(p * 1.0)+1, a_m = ksm(a, m, p);
ll mul = b;
fo(j, 1, m) {
mul = mul * a % p;
h[mul] = j;
}
fo(i, 1, m) {
d = d * a_m % p;
if(h[d]) return i * m - h[d] + k;
}
return -1;
}
int main() {
while(1) {
scanf("%lld %lld %lld", &a, &p, &b);
if(a == 0 && b == 0 && p == 0) return 0;
ll ans = exbsgs(a, b, p);
if(ans == -1) printf("No Solution\n"); else printf("%lld\n", ans);
}
}