洛谷P11175 【模板】基于值域预处理的快速离散对数
题目链接:https://www.luogu.com.cn/problem/P11175
解题思路完全来自 oi.wiki
示例程序:
#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;
int fadd(int x, int y, int p) { return (x + y) % p; }
int fsub(int x, int y, int p) { return (x - y + p) % p; }
int fmul(int x, int y, int p) { return 1ll * x * y % p; }
int fpow(int a, int b, int p) {
int res = 1;
for (int t = a % p; b; b >>= 1, t = fmul(t, t, p))
if (b & 1)
res = fmul(res, t, p);
return res;
}
unordered_map<int, int> mp;
int P, g, L, B, inv, P_1;
int Lg[maxn], p[maxn];
bool vis[maxn];
int cal(int x) {
for (int i = 0, s = x; i <= P / B; i++) {
if (mp.count(s)) {
return i * B + mp[s];
}
s = fmul(s, inv, P);
}
assert(1 == 0);
return -1;
}
void init() {
L = sqrt(P) + 1;
B = sqrtl(1ll * P * sqrt(P) / log(P));
inv = fpow(fpow(g, B, P), P - 2, P); // inv = 1 / (g ^ B)
P_1 = (P - 1) / 2; // g ^ {P_1} = P - 1 (mod P)
for (int i = 0, s = 1; i < B; i++) {
if (mp.count(s))
break;
mp[s] = i;
s = fmul(s, g, P);
}
int idx = 0;
for (int i = 2; i <= L; i++) {
if (!vis[i]) {
p[++idx] = i;
Lg[i] = cal(i);
}
for (int j = 1; j <= idx && p[j] * i <= L; j++) {
vis[ p[j] * i ] = true;
Lg[ p[j] * i ] = fadd(Lg[ p[j] ], Lg[i], P - 1);
if (i % p[j] == 0)
break;
}
}
}
int solve(int y) {
if (y <= L) return Lg[y];
int v = P / y, r = P % y;
if (r < y - r)
return fadd(fsub(solve(r), Lg[v], P-1), P_1, P-1);
else
return fsub(solve(y-r), Lg[v+1], P-1);
}
int main() {
scanf("%d%d", &P, &g);
init();
int q, y;
scanf("%d", &q);
while (q--) {
scanf("%d", &y);
printf("%d\n", solve(y));
}
return 0;
}
浙公网安备 33010602011771号