题解:洛谷 B4002 平方之和
【题目来源】
洛谷:B4002 [GESP202406 二级] 平方之和 - 洛谷
【题目描述】
小杨有n个正整数\(a_1, a_2, \dots, a_n\),他想知道对于所有的\(i(1\le i\le n)\) ,是否存在两个正整数\(x\)和\(y\)满足\(x\times x + y\times y=a_i\)。
【输入】
第一行包含一个正整数\(n\),代表正整数数量。
之后\(n\)行,每行包含一个正整数,代表\(a_i\)。
【输出】
对于每个正整数\(a_i\),如果存在两个正整数\(x\)和\(y\)满足\(x\times x + y\times y=a_i\),输出Yes,否则输出No
【输入样例】
2
5
4
【输出样例】
Yes
No
【核心思想】
-
问题分析:给定 \(n\) 个正整数 \(a_i\),判断每个数是否能表示为两个正整数的平方和,即 \(a_i = x^2 + y^2\)(\(x, y \geq 1\))。这是一个数论判定 + 枚举验证问题,核心在于枚举可能的 \(x\) 值并验证剩余部分是否为完全平方数。
-
算法选择:
- 枚举 \(x\):\(x\) 的范围为 \([1, \lfloor\sqrt{a_i-1}\rfloor]\),因为 \(y \geq 1\) 所以 \(x^2 < a_i\)
- 完全平方数判定:对 \(y^2 = a_i - x^2\),检查其是否为完全平方数
-
关键步骤:
- 读入数据:读取 \(n\)
- 逐数判定(对每个 \(a_i\)):
- \(fl \leftarrow 0\)
- 枚举 \(x\) 从 \(1\) 到 \(\lfloor\sqrt{a_i-1}\rfloor\):
- \(y^2 \leftarrow a_i - x^2\)
- 若 \(check(y^2)\) 为真(即 \(y^2\) 是完全平方数):\(fl \leftarrow 1\),\(break\)
- 若 \(fl = 1\) 输出
Yes,否则输出No
-
时间/空间复杂度:
- 时间复杂度:\(O(n \cdot \sqrt{a_i})\),对每个数枚举到 \(\sqrt{a_i}\)
- 空间复杂度:\(O(1)\)
-
枚举验证的核心思想:
- 正整数约束的处理:题目要求 \(x, y\) 为正整数,因此 \(x \geq 1, y \geq 1\),即 \(x^2 \geq 1, y^2 \geq 1\)。枚举上限为 \(i \cdot i < n\)(即 \(x^2 < a_i\)),确保 \(y^2 = a_i - x^2 \geq 1\)
- 完全平方数的精确判定:通过
sqrt取整后平方还原,与原数比较。注意浮点精度问题,对于大数可能需要使用long long或二分查找替代 - 提前终止优化:一旦找到满足条件的 \((x, y)\) 对立即退出循环,减少不必要的计算
- 费马平方和定理:从数论角度,一个正整数能表示为两整数平方和当且仅当其质因数分解中所有形如 \(4k+3\) 的质因子的指数均为偶数。但直接枚举对于小规模数据更简单直观
- 适用于基础数论判定、平方和分解类入门问题
【算法标签】
入门 #语法基础
【代码详解】
#include <bits/stdc++.h>
using namespace std;
// 判断一个数是否是完全平方数
bool check(int x)
{
int y = sqrt(x); // 计算x的平方根,向下取整
return y * y == x; // 检查y的平方是否等于x
}
int main()
{
int t; // 测试用例数量
cin >> t;
while (t--) { // 处理每个测试用例
int n; // 输入的数字
cin >> n;
int fl = 0; // 标志位,0表示不满足,1表示满足
// 遍历所有可能的i,使得i*i < n
for (int i = 1; i * i < n; i++) {
int j = n - i * i; // 计算差值
if (check(j)) { // 检查j是否是完全平方数
fl = 1; // 如果j是完全平方数,设置标志
break; // 找到就退出循环
}
}
// 输出结果
if (fl)
cout << "Yes" << endl;
else
cout << "No" << endl;
}
return 0;
}
【运行结果】
2
5
Yes
4
No
浙公网安备 33010602011771号