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

✅ 方法二碾压方法一


相关推荐
辛苦才能19 分钟前
C++多态原理:虚函数表的内存布局与动态绑定的汇编真相
开发语言·c++
西西弗Sisyphus29 分钟前
Qt 实现一个 水波进度球
c++·qt·c
无忧.芙桃30 分钟前
数据结构之排序算法(中):冒泡排序与快速排序,从相邻交换到工程级优化
c语言·c++·排序算法
不会就选b30 分钟前
算法日常・每日刷题--<贪心>17
算法
Hhy_110736 分钟前
《C++深度解构04》类和对象(下)——类型转换、static、友元与编译器优化
c语言·c++·学习·类和对象·visual studio
qq_199886871 小时前
第7板块·第1节:通用算子分类与设计模式
c++·人工智能·gpu算力·cuda
6Hzlia3 小时前
【Classic 150 刷题计划】 LeetCode 205. 同构字符串 | C++ 双向绑定与哈希表映射
c++·算法·leetcode
神仙别闹9 小时前
基于 C++ 实现(控制台)学生成绩管理系统
开发语言·c++
会周易的程序员9 小时前
5 节点边缘冗余方案(上):基于 aiRaft 的物联网高可用控制面设计
c++·分布式·物联网·raft·iot·共识
有点。9 小时前
C++03阶段练习(练习题)
数据结构·算法·图论