給質數 P (≤ 2³¹), 基數 B (2 ≤ B < P), 目標 N (1 ≤ N < P)。求最小非負整數 L 使 `B^L ≡ N (mod P)`。無解輸出 "no solution"。多測試案例。
const int MOD = 76543; // 哈希表大小,取質數
int head[MOD], nxt[MAXM], val[MAXM], id[MAXM], ecnt;
void hashInsert(int v, int i) {
int k = v % MOD;
val[ecnt] = v; id[ecnt] = i; nxt[ecnt] = head[k]; head[k] = ecnt++;
}
int hashFind(int v) {
int k = v % MOD;
for (int i = head[k]; ~i; i = nxt[i])
if (val[i] == v) return id[i];
return -1;
}
int BSGS(int a, int b, int p) { // a^L ≡ b (mod p)
if (b == 1) return 0;
memset(head, -1, sizeof(head));
ecnt = 0;
int m = (int)sqrt(p) + 1;
long long v = b;
for (int j = 0; j < m; ++j) {
if (hashFind(v) == -1) hashInsert(v, j); // 保留最小 j
v = v * a % p;
}
long long factor = 1;
for (int i = 0; i < m; ++i) factor = factor * a % p; // a^m
long long cur = 1;
for (int i = 0; i <= m; ++i) {
int j = hashFind(cur);
if (j != -1) {
long long L = 1LL * i * m - j;
if (L >= 0) return (int)L;
}
cur = cur * factor % p;
}
return -1;
}
POJ 2417 是 BSGS 算法的經典模板題。離散對數問題在密碼學中極其重要,BSGS 將 O(P) 降為 O(√P)。掌握「巨步小步」分解與哈希表查找,是數論算法必修課。