1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
| int BSGS(int a, int b) { if (b == 1 || P == 1) return 0; static __gnu_pbds::gp_hash_table<int, int> H; if (H.empty()) { int cur = 1, K = std::sqrt(P) + 1; for (int i = 0; i < K; ++ i, cur = (LL) cur * a % P) H[cur] = i; } int cur, ak, K = std::sqrt(P) + 1, x, y; cur = ak = qpow(a, K); ExGcd(b, P, x, y), x = (x % P + P) % P, cur = (LL) cur * x % P; for (int i = 1; i <= K; ++ i, cur = (LL) cur * ak % P) if (H.find(cur) != H.end()) return i * K - H[cur]; return -1; }
int Phi(int n) { int res = n; for (int i = 2; i <= n / i; ++ i) if (n % i == 0) { res = res / i * (i - 1); while (n % i == 0) n /= i; } if (n != 1) res = res / n * (n - 1); return res; }
int findrt() { std::vector<int> fac; int phi = Phi(P), n = phi; for (int i = 2; i <= n / i; ++ i) if (n % i == 0) { fac.push_back(phi / i); while (n % i == 0) n /= i; } if (n ^ 1) fac.push_back(phi / n); auto check = [&](int x) -> bool { for (int p : fac) if (qpow(x, p) == 1) return false; return true; }; for (int i = 2; i < phi; ++ i) if (check(i)) return i; return -1; }
void tarjan(int x) { dfn[x] = low[x] = ++ *dfn, ins[stk[++ top] = x] = true; for (int v : g[x]) if (!dfn[v]) tarjan(v), chkmin(low[x], low[v]); else if (ins[v]) chkmin(low[x], dfn[v]); if (low[x] ^ dfn[x]) return; int cur; ++ *bel; do ins[cur = stk[top --]] = false, bel[cur] = *bel, sz[*bel] ++; while (cur != x); }
void init() { std::function<int(int)> inv = [&](int i) { return i == 1 ? 1 : (LL) (Mod - Mod / i) * inv(Mod % i) % Mod; }; pw[0] = 1; for (int i = 1; i < N; ++ i) adj(pw[i] = pw[i - 1] * 2 - Mod); for (int i = 0; i < N; ++ i) ipw[i] = inv(pw[i]); }
int main() { init(); std::cin >> n >> P; for (int i = 1; i <= n; ++ i) scanf("%d", a + i); int phi = Phi(P), G = findrt(), frm = 2; for (; P % frm; ++ frm); __gnu_pbds::gp_hash_table<int, int> mp; for (int i = 1; i <= n; ++ i) if (a[i] % frm) a[i] = BSGS(G, a[i]); else mp[a[i]] = i, pp[i] = true; for (int i = 1; i <= n; ++ i) if (pp[i]) { int cur = (LL) a[i] * a[i] % P; while (cur) { if (mp.find(cur) != mp.end()) g[i].push_back(mp[cur]); cur = (LL) cur * a[i] % P; } } for (int i = 1; i <= n; ++ i) for (int j = 1; j <= n; ++ j) if (!pp[i] && !pp[j] && i != j && a[j] % Gcd(phi, a[i]) == 0) g[i].push_back(j); for (int i = 1; i <= n; ++ i) if (!dfn[i]) tarjan(i); for (int x = 1; x <= n; ++ x) for (int v : g[x]) if (bel[x] != bel[v]) h[bel[v]].push_back(bel[x]); int res = 0; for (int x = 1; x <= *bel; ++ x) { std::sort(h[x].begin(), h[x].end()), h[x].erase(std::unique(h[x].begin(), h[x].end()), h[x].end()); int cur = 1; for (int v : h[x]) cur = (LL) cur * ipw[sz[v]] % Mod; res = (res + (LL) cur * (pw[sz[x]] - 1) % Mod * ipw[sz[x]]) % Mod; } res = (LL) res * pw[n] % Mod; std::cout << res << '\n'; return 0; }
|