1 条题解

  • 0
    @ 2025-8-24 22:22:24

    自动搬运

    查看原文

    来自洛谷,原作者为

    avatar Alex_Wei
    **

    搬运于2025-08-24 22:22:24,当前版本为作者最后更新于2022-03-28 21:33:09,作者可能在搬运后再次修改,您可在原文处查看最新版

    自动搬运只会搬运当前题目点赞数最高的题解,您可前往洛谷题解查看更多

    以下是正文


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

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

    究极神仙题。

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

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

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

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

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

    $$\sum\limits_{a + b \equiv x} \left(\left(\dfrac a p\right) + 1\right)\left(\left(\dfrac b p\right) + 1\right) $$

    pp 以内的二次剩余和二次非剩余个数相等,故 $\sum\limits_{i = 0} ^ {p - 1} \left(\dfrac i p\right) = 0$。再根据 bxab \equiv x - a 和勒让德符号的完全积性,上式简化为

    $$p + \sum\limits_{a = 0} ^ {p - 1} \left(\dfrac {ax - a ^ 2} p\right) $$

    接下来是一步巧妙转化。考虑到为 axa2ax - a ^ 2 除以 a2a ^ 2 并不影响它的二次剩余性,因此答案即

    $$p + \sum\limits_{a = 1} ^ {p - 1}\left(\dfrac {\frac x a - 1} p\right) $$

    显然,对于 x0x \neq 0a[1,p1]a \in [1, p - 1]xa\dfrac x a 取遍 [1,p1][1, p - 1],即 xa1\dfrac x a - 1 取遍 [0,p2][0, p - 2]。故当 x0x \neq 0 时,答案又可写为

    p(1p)p - \left(\dfrac {-1}{p}\right)

    根据欧拉判别准则公式 $\left(\dfrac a p\right) \equiv a ^ {\frac {p - 1} 2} \pmod p$ 上式即 p(1)p12p - (-1) ^ {\frac {p - 1} 2}

    对于 x=0x = 0,答案 $p + \sum\limits_{a = 1} ^ {p - 1} \left(\dfrac {-1} p\right)$ 即 p+(p1)(1)p12p + (p - 1)(-1) ^ {\frac {p - 1} 2}

    公式已经足够简洁,可以 O(1)\mathcal{O}(1) 计算。时间复杂度 O(p+nω(p))\mathcal{O}(p + n\omega(p))

    #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;
    }
    
    • 1

    信息

    ID
    5643
    时间
    1100ms
    内存
    512MiB
    难度
    7
    标签
    递交数
    0
    已通过
    0
    上传者