抱歉,您的浏览器无法访问本站

本页面需要浏览器支持(启用)JavaScript


了解详情 >

大步小步法(Baby Step Giant Step, BSGS),用于解决求形如 \(a^x\equiv b \pmod P\) 的最小非负整数解,其中\((a,P)=1\)

求解

显然 \(x\) 可以表示为 \(i\cdot t-j\) 的形式,其中 \(t\) 是常数。那么原方程化为 \[\begin{aligned} a^{it-j} &\equiv b &\pmod P \\ \frac{a^{it}}{a^j} &\equiv b &\pmod P \\ a^{it}&\equiv ba^j &\pmod P \end{aligned}\]

又根据欧拉定理可得,\(a^b\equiv a^{b\bmod \varphi(P)}\pmod P\),所以最小非负整数解一定满足 \(0\le x < \varphi(P)\)

那么 \(t\)\(\lfloor \sqrt{\varphi(P)}\rfloor\) 时,\(i,j\) 的数量都是 \(\mathcal O(\sqrt{P})\) 的。所以我们只要对于所有的 \(i\) 求出 \(a^{it}\),对于所有的 \(j\) 求出 \(ba^j\),然后匹配即可。

具体实现时,可以用 maphashmap 实现快速查找。

代码

「TJOI2007」可爱的质数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <cstdio>
#include <cmath>
#include <map>
int P, a, b;
int BSGS(int a, int b){
a %= P, b %= P;
if (a == 0) return b == 0 ? 1 : -1;
std :: map<int, int> M;
int t = sqrt(P) + 1, x = 1, y;
for (register int i = 0; i < t; ++i, x = 1ll * x * a % P)
M[1ll * x * b % P] = i;
y = x;
if (M.count(1) && M[1] == 0) return 0;
for (register int i = 1; i <= t; ++i, x = 1ll * x * y % P)
if (M.count(x)) return i * t - M[x];
return -1;
}
void write_ans(int x){
if (x < 0) printf("no solution\n");
else printf("%d\n", x);
}
int main(){
scanf("%d%d%d", &P, &a, &b);
write_ans(BSGS(a, b));
}

评论