三類查詢,給定 y, z, p:
y^z mod px*y ≡ z (mod p),求最小非負整數解 xy^x ≡ z (mod p),求最小非負整數解 x(離散對數)
long long mod_pow(long long a, long long b, long long mod) {
long long res = 1 % mod;
a %= mod;
while (b) {
if (b & 1) res = res * a % mod;
a = a * a % mod;
b >>= 1;
}
return res;
}
x*y ≡ z (mod p)轉化為 x*y + k*p = z,即 x*y ≡ z (mod p)。
g = gcd(y, p)z % g != 0 → 無解y*x0 + p*k0 = gx = x0 * (z/g)p/g,取最小非負解
long long exgcd(long long a, long long b, long long &x, long long &y) {
if (!b) { x = 1; y = 0; return a; }
long long x1, y1;
long long g = exgcd(b, a % b, x1, y1);
x = y1;
y = x1 - (a / b) * y1;
return g;
}
long long solve_linear(long long y, long long z, long long p) {
long long x, k;
long long g = exgcd(y, p, x, k);
if (z % g) return -1; // 無解
long long mod = p / g;
x = x * (z / g) % mod;
if (x < 0) x += mod;
return x;
}
y^x ≡ z (mod p) —— BSGS (Baby-Step Giant-Step)核心思想:令 x = i*m - j,其中 m = ceil(sqrt(p))。
y^j mod p 存入哈希表(j = 0..m-1)y^m mod p,迭代 i = 0..m 檢查 z * (y^m)^i mod p 是否在表中x = i*m - j注意處理 y, p 不互質的情況(需先提取公因子)。
#include <unordered_map>
long long bsgs(long long y, long long z, long long p) {
y %= p; z %= p;
if (z == 1) return 0; // y^0 = 1
unordered_map mp;
long long m = ceil(sqrt(p));
long long cur = 1;
for (int j = 0; j < m; j++) {
if (!mp.count(cur)) mp[cur] = j;
cur = cur * y % p;
}
long long factor = mod_pow(y, m, p); // y^m
cur = z;
for (int i = 0; i <= m; i++) {
if (mp.count(cur)) {
long long ans = 1LL * i * m - mp[cur];
if (ans >= 0) return ans;
}
cur = cur * factor % p;
}
return -1; // 無解
}
#include <bits/stdc++.h>
using namespace std;
using ll = long long;
ll mod_pow(ll a, ll b, ll mod) { ... }
ll exgcd(ll a, ll b, ll &x, ll &y) { ... }
ll solve_linear(ll y, ll z, ll p) { ... }
ll bsgs(ll y, ll z, ll p) { ... }
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
int T, k;
while (cin >> T >> k) {
while (T--) {
ll y, z, p; cin >> y >> z >> p;
if (k == 1) {
cout << mod_pow(y, z, p) << '\n';
} else if (k == 2) {
ll ans = solve_linear(y, z, p);
if (ans == -1) cout << "Orz, I cannot find x!\n";
else cout << ans << '\n';
} else {
ll ans = bsgs(y, z, p);
if (ans == -1) cout << "Orz, I cannot find x!\n";
else cout << ans << '\n';
}
}
}
return 0;
}
O(log z)O(log p)O(√p log p)(哈希表查詢)z % g != 0 直接無解;解出來要模 p/g 取最小非負y % p == 0 時特判:z == 0 答案為 1,否則無解y, p 不互質時,標準 BSGS 失效,需先提取公因子遞歸處理(本題測試數據可能保證互質或較弱,但完整解法應處理)unordered_map 或自定義雜湊,注意 cur 可能重複,保留最小 jOrz, I cannot find x!本題綜合考察數論三大核心工具:
掌握這三個模板,可解決絕大多數模數運算相關問題。