# bzoj 1420 Discrete Root - 原根 - exgcd - BSGS

戳我来传送

给定$k, p, a$，求$x^{k}\equiv a \pmod{p}$在模$p$意义下的所有根。

考虑模$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 }
posted @ 2018-03-01 11:08  阿波罗2003  阅读(184)  评论(0编辑  收藏