[Solution && Learning Record] exBSGS
FifthAxiom · · 题解
\text{BSGS} 算法
概念
BSGS 算法用于求解离散对数同余方程
算法
我们先讨论
首先由欧拉定理可以知道
而又知
设
这样通过枚举
发现
用一个 Hash 表将右边所有的取值与
Q & A
Q : 为什么
x 一定要从1 开始枚举?A : 考虑
x=0 的情况,如果继续上面的枚举,那么相当于求1\equiv ba^y\pmod{p} ,这样的y 一定是负数,而 BSGS 求解的t 经常要求是非负整数。所以从1 开始枚举。
exBSGS
此时不要求
注意到
令
-
-
$$ \begin{aligned} &\dfrac{a}{d}a^{t-1}+k\dfrac{p}{d}=\dfrac{b}{d}\\ \Leftrightarrow & \dfrac{a}{d}a^{t-1}\equiv \dfrac{b}{d}\pmod{\dfrac{p}{d}}\\ \Leftrightarrow & a^{t-1}\equiv \dfrac{b}{d}\cdot\left(\dfrac{a}{d}\right)^{-1}\pmod{\dfrac{p}{d}}\\ \end{aligned} $$
如果
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <unordered_map>
using namespace std;
typedef long long LL;
const int INF = 0x3f3f3f3f;
int a, b, p;
unordered_map<int, int> hs;
int exgcd(int a, int b, int &x, int &y) {
if (!b) {
x = 1, y = 0;
return a;
}
int d = exgcd(b, a % b, y, x);
y -= a / b * x;
return d;
}
int BSGS(int a, int b, int p) {
if (1 % p == b % p) return 0;
int k = sqrt(p) + 1;
hs.clear();
for (int y = 0, r = b % p; y < k; y++) {
hs[r] = y;
r = (LL)r * a % p;
}
int ak = 1;
for (int i = 1; i <= k; i++) ak = (LL)ak * a % p;
for (int x = 1, l = ak; x <= k; x++) {
if (hs.count(l)) return k * x - hs[l];
l = (LL)l * ak % p;
}
return -INF;
}
int exBSGS(int a, int b, int p) {
b = (b % p + p) % p;
if (1 % p == b % p) return 0;
int x, y;
int d = exgcd(a, p, x, y);
if (d > 1) {
if (b % d) return -INF;
exgcd(a / d, p / d, x, y);
return exBSGS(a, (LL)b / d * x % (p / d), p / d) + 1;
}
return BSGS(a, b, p);
}
int main() {
while (~scanf("%d%d%d", &a, &p, &b), a || b || p) {
int res = exBSGS(a, b, p);
if (res < 0) puts("No Solution");
else printf("%d\n", res);
}
return 0;
}