


🟦 题目名称:平方之和
🌈 一、先看题目
小杨手里有很多正整数。
1、他想知道:
每一个数 n,
能不能写成
两个正整数的平方之和?
2、也就是问:
cpp
是否存在 a 和 b
使得:
a² + b² = n
3、如果可以,输出:
cpp
Yes
4、否则输出:
cpp
No
🧸 二、什么是"完全平方数"?
1、完全平方数就是:
整数 * 整数(自己)= 完全平方数
2、例如:
| 数字 | 完全平方数 |
|---|---|
| 1 | 1 |
| 2 | 4 |
| 3 | 9 |
| 4 | 16 |
| 5 | 25 |
🎈 三、举例理解
1、🌟 例子1
(1)输入:
cpp
5
(2)问:5 能不能表示成两个完全平方数的和?
(3)我们试试看:
cpp
1² + 2² = 1 + 4 = 5
(4)可以!
(5)所以输出:
cpp
Yes
🌟 例子2
(1)输入:
cpp
4
(2)试试看:
1² + 1² = 2
1² + 2² = 5
2² + 2² = 8
没有办法等于 4。
(3)所以输出:
cpp
No
🧠 四、解题思路
1、我们要试所有的可能性。
2、寻找方法:
cpp
for a 从 1 开始
3、计算:
cpp
剩下的 = n - a²
4、然后看看:
👉 剩下的这个数是不是一个"完全平方数"?
5、如果是!
说明找到了!
6、如果不是!
就去继续找!
7、一直到
找完所有可能性!
🧮 五、怎么判断"是不是完全平方数"?
1、例如:
16
2、我们可以:
cpp
int y = sqrt(16);
3、如果:
cpp
y*y == 16
说明是平方数。
💻 六、参考代码
cpp
#include<bits/stdc++.h>
using namespace std;
bool check(int x){ //判断是否是完全平方数
int y = sqrt(x);
return y*y==x;
}
int main(){
int t;
cin>>t;
while(t--){
int n;
cin>>n;
int flag = 0;
for(int i=1;i*i<n;i++){ //枚举其中一个数字
int j = n-i*i;
if(check(j)) //判断另外一个数字
flag = 1;
}
if(flag)
cout<<"Yes\n";
else
cout<<"No\n";
}
}
💻 七、代码讲解:
1、参考代码:
cpp
bool check(int x){
int y = sqrt(x);
return y*y==x;
}
这段代码返回值为
是否是"完全平方数"。
2、主程序:
cpp
for(int i=1;i*i<n;i++){
int j=n-i*i;
if(check(j))
flag=1;
}
枚举所有可能性:
cpp
j = n - i²
如果 j 是平方数
说明成功
🧮 八、本题的查询数字的个数n,如果n是10万,怎么办?
1、可以对数字进行预先处理
先用双重循环枚举 x 和 y
把所有 x² + y² 的结果存到数组里
后面每次输入 ai 直接查表
每次查询时间都是O(1)
2、参考程序:
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1000000;
bool ok[MAXN + 1];
int main() {
// 预处理
for(int x = 1; x*x <= MAXN; x++){
for(int y = x; y*y <= MAXN; y++){ // y 从 x 开始
int sum = x*x + y*y;
if(sum > MAXN)
break;
ok[sum] = true;
}
}
int n;
cin >> n;
while(n--){
int a;
cin >> a;
if(ok[a])
cout << "Yes\n";
else
cout << "No\n";
}
return 0;
}
3、👉这是 典型的"预处理 + 查表"
这是非常重要的算法思想!
在后面:
埃氏筛法
前缀和
动态规划
都会用到。
🧠 九、 两种方法比较
1、✅ 方法一:每个 ai 单独枚举(逐个判断)
(1)核心思想:
cpp
对每个 ai:
枚举 a
判断 n - a² 是否为平方数
(2)时间复杂度:
cpp
O(n × √ai)
2、✅ 方法二:预处理 + 查表
(1)核心思想:
cpp
先算出所有 x²+y² ≤ 10^6
标记到数组 ok[]
之后每个 ai 直接查 ok[ai]
(2)时间复杂度:
cpp
预处理:O(1000×1000) ≈ 10^6
查询:O(n)
3、🌈 时间复杂度对比
假设:
cpp
ai ≤ 10^6
√10^6 = 1000
(1)🌟 情况1:n 很小(比如本题: n ≤ 10)
cpp
n < 10
(2)方法一:
cpp
最多 10 × 1000 = 10000 次
非常小。
(3)方法二:
cpp
固定做 1000000 次预处理
反而多做了 100 倍的工作。
(4)👉 所以在本题数据范围下:
✅ 方法一更优
4、🌈 什么时候方法二更有优势?
(1)假设:
cpp
n = 100000
(2)方法一:
cpp
100000 × 1000 = 100,000,000 次
一亿次!
(3)方法二:
cpp
预处理 1,000,000 次
查询 100000 次
总共 1,100,000 次
快 100 倍。
(4)👉 当 n 很大时:
✅ 方法二碾压方法一