P6610 [Code+#7]同余方程

· · 题解

*II. P6610 [Code+#7]同余方程

基础数论学习笔记 Part 7 例 2。

究极神仙题。

根据 \mu(p) \neq 0 不难想到使用 CRT 将问题拆分为模奇质数。每个奇质数的解的个数的积即为所求,因为从每个奇质数的解中任选一个,根据中国剩余定理,所有奇质数对应的解组合起来唯一确定一个解。

拆成奇质数是为了使二次剩余相关定理适用。接下来 p 均视为奇质数。

问题转化为求解 x 能被拆分成多少组 a, b 的和,使得 a, b 均为二次剩余或 0。其中,每个二次剩余的贡献系数是 2(一个二次剩余可被表示两个数的平方),0 的贡献是 1,每组 (a, b) 的贡献即 ab 分别的贡献系数之积。

我们需要一个数学公式而非判断式来描述答案,因为判断式是不可化简的。

二次剩余对应 20 对应 1,二次非剩余对应 0,这使得我们想到勒让德符号:注意到 \left(\dfrac a p\right) + 1 等价于使得 x ^ 2 \equiv a \pmod px 的个数,因此答案为

\sum\limits_{a + b \equiv x} \left(\left(\dfrac a p\right) + 1\right)\left(\left(\dfrac b p\right) + 1\right) $$ p + \sum\limits_{a = 0} ^ {p - 1} \left(\dfrac {ax - a ^ 2} p\right) $$ 接下来是一步巧妙转化。考虑到为 $ax - a ^ 2$ 除以 $a ^ 2$ 并不影响它的二次剩余性,因此答案即 $$ p + \sum\limits_{a = 1} ^ {p - 1}\left(\dfrac {\frac x a - 1} p\right) $$ 显然,对于 $x \neq 0$ 且 $a \in [1, p - 1]$,$\dfrac x a$ 取遍 $[1, p - 1]$,即 $\dfrac x a - 1$ 取遍 $[0, p - 2]$。故当 $x \neq 0$ 时,答案又可写为 $$ p - \left(\dfrac {-1}{p}\right) $$ 根据欧拉判别准则公式 $\left(\dfrac a p\right) \equiv a ^ {\frac {p - 1} 2} \pmod p$ 上式即 $p - (-1) ^ {\frac {p - 1} 2}$。 对于 $x = 0$,答案 $p + \sum\limits_{a = 1} ^ {p - 1} \left(\dfrac {-1} p\right)$ 即 $p + (p - 1)(-1) ^ {\frac {p - 1} 2}$。 公式已经足够简洁,可以 $\mathcal{O}(1)$ 计算。时间复杂度 $\mathcal{O}(p + n\omega(p))$。 ```cpp #include <bits/stdc++.h> using namespace std; const int N = 1e7 + 5; int T, p, x, cnt, ans = 1, pr[N], mnpr[N]; bool vis[N]; int calc(int x, int p) {return !x ? p % 4 == 1 ? 2 * p - 1 : 1 : p - (p % 4 == 1 ? 1 : -1);} int main() { for(int i = 2; i < N; i++) { if(!vis[i]) mnpr[i] = pr[++cnt] = i; for(int j = 1; j <= cnt && i * pr[j] < N; j++) { vis[i * pr[j]] = 1, mnpr[i * pr[j]] = pr[j]; if(i % pr[j] == 0) break; } } cin >> T; while(T--) { cin >> p >> x, ans = 1; while(p != 1) ans *= calc(x % mnpr[p], mnpr[p]), p /= mnpr[p]; cout << ans << "\n"; } return 0; } ```