intsolve(int a, int b, int n){ std::unordered_map<int, int> umap; int S = std::ceil(std::sqrt(n * 1.0)); // 根号 n 上取整
int t = 1; for (int B = 0; B <= S; B++) { umap[1ll * b * t % p] = B; // 对于 -B 部分,如果其余数相同,我们当然保留更大的 B. t = 1ll * t * a % p; } // 枚举 ba^B 部分
int fac = fpow(a, S, p); // 计算 a^S t = 1; int ans = (1ll << 31) - 1; for (int A = 0; A <= S; A++) { auto it = umap.find(t); if (it != umap.end()) { int val = norm(1ll * A * S - it->second, n - 1); ans = std::min(ans, val); // 取最小值. } t = 1ll * t * fac % p; } // 枚举 a^{AS} 部分
return ans >= n ? -1 : ans; // 如果 ans >= n 说明循环内部没有产生更新,即没有找到解. }
intsolve(int a, int b, int n){ a %= n; b %= n; // 特判:若 b==1 或 n==1 直接让 x=0 即可 if (b == 1 || n == 1) return0;
// 快速幂函数 auto fpow = [](int b, int p, int m) { int res = 1; for (; p; p >>= 1, b = 1ll * b * b % m) if (p & 1) res = 1ll * res * b % m; return res; }; // exgcd 求逆元,因为模数 n 可能是偶数 auto exgcd = [&](auto F, int a, int b, int &x, int &y) -> int { if (!b) return x = 1, y = 0, a; else { int g = F(F, b, a % b, y, x); y -= a / b * x; return g; } }; // 取模,映射到 [0, n-1] auto norm = [](int val, int n) { return val %= n, val += (val < 0 ? n : 0); }; // 用 exgcd 求解逆元 auto inv = [norm, exgcd](int val, int m) { int x, y; int g = exgcd(exgcd, val, m, x, y); return g == 1 ? norm(x, m) : -1; }; // 普通 Baby-Step Giant-Step 算法,处理的情况是 (a,n)=1 // 普通 BSGS 算法流程可以参考上文 auto bsgs = [fpow](int a, int b, int n) { int m = 1 + std::sqrt(n * 1.0); std::unordered_map<int, int> u;
for (int i = 0, t = b % n; i < m; i++) { u[t] = i; t = 1ll * t * a % n; } int factor = fpow(a, m, n); int res = (1ll << 31) - 1; for (int i = 0, t = 1 % n; i <= m; i++) { auto it = u.find(t); if (it != u.end()) { int x = 1ll * i * m - it->second; if (x >= 0) return x; } t = 1ll * t * factor % n; } return-1; };
// 计算 D 值 // 这里其实一边计算 D 和 gcd,一边在 b,n,a 里面同时除掉 gcd. // 同时,这里 if(ak == b) 也同时测试了前几个 k 值 int k = 0, ak = 1 % n; while (true) { int g = std::gcd(a, n); if (g == 1) break; if (b % g != 0) return-1; n /= g, b /= g; ak = 1ll * ak * (a / g) % n; k++; if (ak == b) return k; a %= n; }
// 这里把 a^k/D 移项到等式右侧 auto iv = inv(ak, n); if (iv == -1) return-1; b = 1ll * b * iv % n;
// 调用 BSGS 算法计算解 auto res = bsgs(a % n, b, n); return res == -1 ? -1 : res + k; // 记得把 k 加回去 }