bzoj 1420 Discrete Root - 原根 - exgcd - BSGS
考虑模$p$下的某个原根$g$。
那么$x = g^{ind_{g}x}, a = g^{ind_{g}a}$。
所以原方程转化为$g^{k\cdot ind_{g}x}\equiv g^{ind_{g}a} \pmod{p}$。
所以方程等价于$k\cdot ind_{g}x \equiv ind_{g}a \pmod{\varphi(p)}$。
用exgcd解出$ind_{g}x$的所有可能的解,再用快速幂算出$x$即可。
Code
1 /** 2 * bzoj 3 * Problem#1420 4 * Accepted 5 * Time: 44ms 6 * Memory: 2032k 7 */ 8 #include <bits/stdc++.h> 9 #include <ext/pb_ds/hash_policy.hpp> 10 #include <ext/pb_ds/assoc_container.hpp> 11 using namespace std; 12 using namespace __gnu_pbds; 13 typedef bool boolean; 14 15 typedef class HashMap { 16 private: 17 static const int M = 46666; 18 public: 19 int ce; 20 int h[M], key[M], val[M], next[M]; 21 22 HashMap() { } 23 24 void insert(int k, int v) { 25 int ha = k % M; 26 for (int i = h[ha]; ~i; i = next[i]) 27 if (key[i] == k) { 28 val[i] = v; 29 return; 30 } 31 ++ce, key[ce] = k, val[ce] = v, next[ce] = h[ha], h[ha] = ce; 32 } 33 34 int operator [] (int k) { 35 int ha = k % M; 36 for (int i = h[ha]; ~i; i = next[i]) 37 if (key[i] == k) 38 return val[i]; 39 return -1; 40 } 41 42 void clear() { 43 ce = -1; 44 memset(h, -1, sizeof(h)); 45 } 46 }HashMap; 47 48 void exgcd(int a, int b, int& d, int& x, int& y) { 49 if (!b) 50 d = a, x = 1, y = 0; 51 else { 52 exgcd(b, a % b, d, y, x); 53 y -= (a / b) * x; 54 } 55 } 56 57 int qpow(int a, int pos, int p) { 58 int pa = a, rt = 1; 59 for ( ; pos; pos >>= 1, pa = pa * 1ll * pa % p) 60 if (pos & 1) 61 rt = rt * 1ll * pa % p; 62 return rt; 63 } 64 65 int inv(int a, int n) { 66 int d, x, y; 67 exgcd(a, n, d, x, y); 68 return (x < 0) ? (x + n) : (x); 69 } 70 71 int p, k, a; 72 int g; 73 74 inline void init() { 75 scanf("%d%d%d", &p, &k, &a); 76 } 77 78 HashMap mp; 79 int ind(int a, int b, int p) { 80 mp.clear(); 81 int cs = sqrt(p - 0.5), ac = qpow(a, cs, p), iac = b * 1ll * inv(ac, p) % p, pw = 1; 82 for (int i = cs - 1; ~i; i--) 83 iac = iac * 1ll * a % p, mp.insert(iac, i); 84 for (int i = 0; i < p; i += cs, pw = pw * 1ll * ac % p) 85 if (~mp[pw]) 86 return mp[pw] + i; 87 return -1; 88 } 89 90 int top = 0; 91 int fac[50]; 92 void getfactors(int x) { 93 for (int i = 2; i * i <= x; i++) { 94 if (!(x % i)) { 95 fac[++top] = i; 96 while (!(x % i)) x /= i; 97 } 98 } 99 if (x != 1) fac[++top] = x; 100 } 101 102 boolean isroot(int x) { 103 int pos = p - 1; 104 for (int i = 1; i <= top; i++) 105 if (qpow(x, pos / fac[i], p) == 1) 106 return false; 107 return true; 108 } 109 110 inline void solve() { 111 if (p == 1 || !a) { 112 printf("1\n0"); 113 return; 114 } 115 if (p == 2) 116 g = 1; 117 else { 118 getfactors(p - 1); 119 for (g = 2; !isroot(g); g++); 120 } 121 122 int inda = ind(g, a, p), d, x, y, cir; 123 exgcd(k, p - 1, d, x, y); 124 if (inda % d) { 125 puts("0"); 126 return; 127 } 128 cir = (p - 1) / d; 129 x = x * 1ll * (inda / d) % cir; 130 (x <= 0) ? (x += cir) : (0); 131 vector<int> res; 132 for (; x < p; x += cir) 133 res.push_back(qpow(g, x, p)); 134 sort(res.begin(), res.end()); 135 printf("%d\n", (signed) res.size()); 136 for (int i = 0; i < (signed) res.size(); i++) 137 printf("%d\n", res[i]); 138 } 139 140 int main() { 141 init(); 142 solve(); 143 return 0; 144 }