从这里开始
离散对数和BSGS算法
设$x$是最小的非负整数使得$a^{x}\equiv b\ \ \ \pmod{m}$,则$x$是$b$以$a$为底的离散对数,记为$x = ind_{a}b$。
假如给定$a, b, m$,考虑如何求$x$,或者输出无解,先考虑$(a, m) = 1$的情况。
定理1(欧拉定理) 若$(a, m) = 1$,则$a^{\varphi(m)}\equiv 1 \pmod{m}$。
证明这里就不给出,因为在百度上随便搜一搜就能找到。
不过,这个定理告诉我们,在$(a, m) = 1$的情况下,若存在答案,则答案不会超过$\varphi(m) - 1$。
考虑$a^{x} \equiv b \pmod{m}$,通过一些操作可以得到:
$a^{x - k} \equiv a^{-k}b \pmod{m}$
因此可以选取正整数$c$,将$x$表示为$ic + j$的形式,然后有:
$a^{ic} \equiv a^{-j}b \pmod{m}$
考虑预处理$a^{-j}b$,以它的值为键,最小的$j$为值存入Hash表或者Map中。
这样有什么用呢?你可以快速枚举$a^{ic}$,然后你将这个值在Hash表中查一查对应的最小的$j$,如果查到就可以得到答案了。
Code
1 /** 2 * poj 3 * Problem#2417 4 * Accepted 5 * Time: 16ms 6 * Memory: 1372l 7 */ 8 #include <iostream> 9 #include <cstring> 10 #include <cstdio> 11 #include <cmath> 12 using namespace std; 13 typedef bool boolean; 14 15 int p, x, a; 16 17 typedef class HashMap { 18 private: 19 static const int M = 46666; 20 public: 21 int ce; 22 int h[M], key[M], val[M], next[M]; 23 24 HashMap():ce(-1) { } 25 26 void insert(int k, int v) { 27 int ha = k % M; 28 for (int i = h[ha]; ~i; i = next[i]) 29 if (key[i] == k) { 30 val[i] = v; 31 return; 32 } 33 ++ce, key[ce] = k, val[ce] = v, next[ce] = h[ha]; 34 h[ha] = ce; 35 } 36 37 int operator [] (int k) { 38 int ha = k % M; 39 for (int i = h[ha]; ~i; i = next[i]) 40 if (key[i] == k) 41 return val[i]; 42 return -1; 43 } 44 45 void clear() { 46 ce = -1; 47 memset(h, -1, sizeof(h)); 48 } 49 }HashMap; 50 51 int qpow(int a, int pos) { 52 int pa = a, rt = 1; 53 for (; pos; pos >>= 1, pa = pa * 1ll * pa % p) 54 if (pos & 1) 55 rt = rt * 1ll * pa % p; 56 return rt; 57 } 58 59 void exgcd(int a, int b, int& d, int &x, int &y) { 60 if (!b) 61 d = a, x = 1, y = 0; 62 else { 63 exgcd(b, a % b, d, y, x); 64 y -= (a / b) * x; 65 } 66 } 67 68 int inv(int a, int n) { 69 int d, x, y; 70 exgcd(a, n, d, x, y); 71 return (x < 0) ? (x + n) : (x); 72 } 73 74 inline boolean init() { 75 return ~scanf("%d%d%d", &p, &x, &a); 76 } 77 78 int cs; 79 HashMap mp; 80 inline int ind() { 81 mp.clear(); 82 cs = sqrt(p - 1 + 0.5); 83 if (cs == 0) cs++; 84 int ainv = inv(x, p), iap = a * 1ll * qpow(ainv, cs - 1) % p; 85 for (int i = cs - 1; ~i; i--, iap = iap * 1ll * x % p) 86 mp.insert(iap, i); 87 int cp = qpow(x, cs), pw = 1; 88 for (int i = 0; i < p; i += cs, pw = pw * 1ll * cp % p) 89 if (~mp[pw]) 90 return mp[pw] + i; 91 return -1; 92 } 93 94 inline void solve() { 95 int res = ind(); 96 if (res == -1) 97 puts("no solution"); 98 else 99 printf("%d\n", res); 100 } 101 102 int main() { 103 while (init()) 104 solve(); 105 return 0; 106 }