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 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> 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 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); } ``` ## 扩展篇 接下来我们求解 $$ a^x\equiv b\pmod p $$ 其中 $a,p$ 不一定互质。 当 $a\perp p$ 时,在模 $p$ 意义下 $a$ 存在逆元,因此可以使用 BSGS 算法求解。于是我们想办法让他们变得互质。 具体地,设 $d_1=\gcd(a,p)$ 。如果 $d_1\nmid b$ ,则原方程无解。否则我们把方程同时除以 $d_1$ ,得到 $$ \frac{a}{d_1}\cdot a^{x-1}\equiv \frac{b}{d_1}\pmod{\frac{p}{d_1}} $$ 如果 $a$ 和 $\frac{p}{d_1}$ 仍不互质就再除,设 $d_2=\gcd\left(a,\frac{p}{d_1}\right)$ 。如果 $d_2\nmid \frac{b}{d_1}$ ,则方程无解;否则同时除以 $d_2$ 得到 $$ \frac{a^2}{d_1d_2}\cdot a^{x-2}≡\frac{b}{d_1d_2} \pmod{\frac{p}{d_1d_2}} $$ 同理,这样不停的判断下去。直到 $a\perp \frac{p}{d_1d_2\cdots d_k}$ 。 记 $D=\prod_{i=1}^kd_i$ ,于是方程就变成了这样: $$ \frac{a^k}{D}\cdot a^{x-k}\equiv\frac{b}{D} \pmod{\frac{p}{D}} $$ 由于 $a\perp\frac{p}{D}$ ,于是推出 $\frac{a^k}{D}\perp \frac{p}{D}$ 。这样 $\frac{a^k}{D}$ 就有逆元了,于是把它丢到方程右边,这就是一个普通的 BSGS 问题了,于是求解 $x-k$ 后再加上 $k$ 就是原方程的解啦。 注意,不排除解小于等于 $k$ 的情况,所以在消因子之前做一下 $\Theta(k)$ 枚举,直接验证 $a^i\equiv b \pmod p$ ,这样就能避免这种情况。 ## 习题 - [SPOJ MOD](https://www.spoj.com/problems/MOD/) 模板 - [SDOI2013 随机数生成器](https://www.luogu.com.cn/problem/P3306) - [SGU261 Discrete Roots](https://codeforces.com/problemsets/acmsguru/problem/99999/261) 模板 - [SDOI2011 计算器](https://loj.ac/problem/10214) 模板 - [Luogu4195【模板】exBSGS/Spoj3105 Mod](https://www.luogu.com.cn/problem/P4195) 模板 - [Codeforces - Lunar New Year and a Recursive Sequence](https://codeforces.com/contest/1106/problem/F) - [LOJ6542 离散对数](https://loj.ac/problem/6542) 模板 **本页面部分内容以及代码译自博文 [Дискретное извлечение корня](http://e-maxx.ru/algo/discrete_root) 与其英文翻译版 [Discrete Root](https://cp-algorithms.com/algebra/discrete-root.html) 。其中俄文版版权协议为 Public Domain + Leave a Link;英文版版权协议为 CC-BY-SA 4.0。**