问题
求解 $$x^a\equiv b(mod \ p)$$
其中 $p$ 为质数
分析
由于 $p$ 为质数,肯定存在原根 $g$。
由原根的定义知 $x$ 可表示成 $x=g^c$,问题转化为 $(g^c)^a \equiv b(mod \ p)$,得到
$$(g^a)^c \equiv b(mod \ p)$$
于是就转换成我们熟悉的BSGS模型了,可以在 $O(\sqrt p logp)$ 解出 $c$。
这样得到原方程的一个特解 $x_0 \equiv g^c(mod \ p)$。显然,这个解不一定是最小解。
如何求出最小解呢?
由于存在取模操作,需要求出所有解。
如何求出所有解呢?
已知 $x0=g^c$ 为其中一个解,设另外一个解 $g^{c+ delt}$ ,有
$$(g^{c+delt})^a \equiv b(mod \ p)$$
推出 $g^{delt\cdot a} \equiv 1(mod \ p)$,进一步有 $delt \cdot a \mid \varphi (p)$,所以 $delt$ 最小为 $delt = \frac{\varphi (p)}{gcd(a, \varphi (p))}$.
易知,$g^{c+k * delt}$ 都是方程的解。
//下面贴出求所有解的模板,注意可能爆int!!
int gcd(int a, int b) { return a ? gcd(b % a, a) : b; } int powmod(int a, int b, int p) { int res = 1; while (b > 0) { if (b & 1) res = res * a % p; a = a * a % p, b >>= 1; } return res; } // Finds the primitive root modulo p int generator(int p) { vector<int> fact; int phi = p - 1, n = phi; for (int i = 2; i * i <= n; ++i) { if (n % i == 0) { fact.push_back(i); while (n % i == 0) n /= i; } } if (n > 1) fact.push_back(n); for (int res = 2; res <= p; ++res) { bool ok = true; for (int factor : fact) { if (powmod(res, phi / factor, p) == 1) { ok = false; break; } } if (ok) return res; } return -1; } // This program finds all numbers x such that x^k=a (mod n) int main() { int n, k, a; scanf("%d %d %d", &n, &k, &a); if (a == 0) return puts("1\n0"), 0; int g = generator(n); // Baby-step giant-step discrete logarithm algorithm int sq = (int)sqrt(n + .0) + 1; vector<pair<int, int>> dec(sq); for (int i = 1; i <= sq; ++i) dec[i - 1] = {powmod(g, i * sq * k % (n - 1), n), i}; sort(dec.begin(), dec.end()); int any_ans = -1; for (int i = 0; i < sq; ++i) { int my = powmod(g, i * k % (n - 1), n) * a % n; auto it = lower_bound(dec.begin(), dec.end(), make_pair(my, 0)); if (it != dec.end() && it->first == my) { any_ans = it->second * sq - i; break; } } if (any_ans == -1) return puts("0"), 0; // Print all possible answers int delta = (n - 1) / gcd(k, n - 1); vector<int> ans; for (int cur = any_ans % delta; cur < n - 1; cur += delta) ans.push_back(powmod(g, cur, n)); sort(ans.begin(), ans.end()); printf("%d\n", ans.size()); for (int answer : ans) printf("%d ", answer); }