GESP2024年6月认证C++二级( 第三部分编程题(1) 平方之和)


🟦 题目名称:平方之和


🌈 一、先看题目

小杨手里有很多正整数。

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 很大时:

✅ 方法二碾压方法一


相关推荐
追随者永远是胜利者1 小时前
(LeetCode-Hot100)64. 最小路径和
java·算法·leetcode·职场和发展·go
StandbyTime1 小时前
《算法笔记》练习记录-2.5-问题 C: 习题6-6 杨辉三角
c++·算法笔记
云深处@1 小时前
【题】每日一题
算法
MR_Promethus2 小时前
【C++11】condition_variable 条件变量
c++·条件变量·并发编程
智者知已应修善业2 小时前
【排列顺序判断是否一次交换能得到升序】2025-1-28
c语言·c++·经验分享·笔记·算法
fpcc2 小时前
并行编程实战——CUDA编程的内存建议
c++·cuda
yzs873 小时前
OLAP数据库HashJoin性能优化揭秘
数据库·算法·性能优化·哈希算法
好家伙VCC3 小时前
**发散创新:编译器优化实战——从LLVM IR到性能飞跃的奇妙旅程**
java·开发语言·python·算法
季明洵3 小时前
数据在内存中的存储
数据结构·算法·c