1 条题解
-
0
✅ 题目简述
我们要在多个指定的区间 $[L, U]$ 中,统计:
- 区间内的所有素数个数;
- 其中可以写作 $p = a^2 + b^2$ 的素数个数。
根据费马定理(Fermat's theorem on sums of two squares),满足以下条件的奇素数 $p$ 可以写成两个整数平方的和:
- $p \equiv 1 \pmod{4}$
另外,$2 = 1^2 + 1^2$ 也符合该条件。
💡 示例输入输出说明
输入示例:
10 20 11 19 100 1000 -1 -1
输出示例:
10 20 4 2 11 19 4 2 100 1000 143 69
🧠 思路说明
-
预处理素数:使用线性筛法生成所有 $[2, 10^6]$ 范围内的素数;
-
处理每组输入区间 $[L, U]$:
- 遍历所有预处理得到的素数;
- 判断该素数是否在区间内;
- 判断是否满足 $p = 4k + 1$ 或 $p = 2$;
- 分别统计总数和平方和素数数目;
-
输出格式严格遵循:
L U x y
✅ 完整带注释的 C++ 代码
#include <cstdio> #include <cstring> #include <algorithm> using namespace std; // 素数数组 a,合数标记数组 check,top 记录素数个数 int a[1100000], check[1100000], top; // 线性筛法生成所有小于等于 10^6 的素数 void f() { top = 0; memset(check, 0, sizeof(check)); for (int i = 2; i <= 1000000; i++) { if (!check[i]) a[top++] = i; // i 是素数,加入数组 for (int j = 0; j < top; j++) { if (i * a[j] > 1000000) break; // 防止越界 check[i * a[j]] = 1; // 标记为合数 if (i % a[j] == 0) break; // 保证每个数只被最小素因子筛一次 } } } int main() { f(); // 预处理素数 int l, r; while (scanf("%d %d", &l, &r) != EOF) { if (l == -1 && r == -1) break; // 终止条件 int total_primes = 0, sum_of_squares_primes = 0; for (int i = 0; i < top; i++) { if (a[i] > r) break; // 超出右边界,退出 if (a[i] >= l) { // 素数在区间内 total_primes++; // 若为 2 或 满足 p ≡ 1 (mod 4),计入平方和素数 if (a[i] == 2 || (a[i] - 1) % 4 == 0) sum_of_squares_primes++; } } printf("%d %d %d %d\n", l, r, total_primes, sum_of_squares_primes); } return 0; }
📌 复杂度分析
操作 时间复杂度 筛素数 $O(n)$,其中 $n = 10^6$ 每组区间查询 最多 $O(\text{素数总数})$,约 $78,498$ 个 由于素数在 $10^6$ 内大约有 $7.8$ 万个,因此即使每组都遍历全部素数,也可在合理时间内完成。
- 1
信息
- ID
- 2512
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 5
- 已通过
- 1
- 上传者