作为带过好几届GESP考生的编程老师,我每年都能看到不少孩子在一级考试里栽跟头。说实话,GESP一级的题目难度并不高,核心就是考基础语法和简单逻辑,但很多孩子不是不会写代码,而是读不懂题、想不到用哪种思路去解,或者明明写对了却因为细节丢分。这次我想以2026年3月这场考试的样题风格为基础,挑一道特别典型的题目——"交朋友"——来完整拆解一遍:从读题、建模、选算法,到写代码、调试、拿满分,整个过程我都会用带学生的真实经验来讲。
这道题的定位很适合作为一级备考的"试金石"。它不考任何高深算法,纯粹考察数组存储、循环遍历、条件判断和计数累加这四个基本功。换句话说,只要孩子能把这几块基础打牢,这类题目就是送分题;反过来,如果这类题目还做得磕磕绊绊,那说明基础语法还没过关,需要回头补。所以不管你是在备考生、刚入门的编程爱好者,还是陪着孩子备考的家长,这篇文章都能帮你把一级的核心考点彻底吃透。
1. 先搞清楚"交朋友"这道题到底在问什么
1.1 从题目描述提取有效信息
GESP一级的题目有个共同特点:题干通常不长,描述也很生活化,但里面藏着的关键信息一点不少。"交朋友"这道题,题目背景大概是这样的:班里有一群小朋友,每个小朋友都有一个"性格值",老师规定,如果两个小朋友的性格值加起来正好等于某个数,那他们就适合交朋友,现在要统计全班一共有多少对这样的小朋友。
很多孩子看到这种题第一反应是"这有什么难的",但一动笔就出错。问题出在哪?出在题干里的几个关键约束没有抓住。一是"一对"这个概念,两个小朋友才能组成一对,而且是无序的,A和B能交朋友,B和A是同一对,不能重复数;二是"每个小朋友只能跟别人组队",也就是说自己不能跟自己配对;三是到底用数组存数据之后,该用什么顺序去遍历才能保证每对只数一次。
所以我在带学生的时候,第一步永远不是上手写代码,而是先带着他们画一张表:题目给了哪些输入,要求什么输出,有什么隐藏条件。对于"交朋友"这道题来说,输入就是n个小朋友的性格值数组和一个目标值k,输出就是满足条件的小对数。至于隐藏条件,最常见的就是不能重复计数、不能自配对,以及n的范围决定了你用什么复杂度的算法。
1.2 一级考纲范围与本题的对应关系
GESP一级的考纲是固定的,主要就这几大块:变量与数据类型、输入输出、顺序结构、分支结构、循环结构、一维数组、以及简单的问题模拟。"交朋友"这道题看起来简单,实际上把这些考点全串起来了。数组用来存性格值,循环用来遍历所有小朋友,分支结构用来判断两个性格值之和是否等于k,最后用一个计数器变量完成累加输出。
所以我常跟学生说,这道题是一级考试的"全套体检":你数组的声明和下标访问熟不熟练、for循环嵌套会不会写、if判断条件有没有写对、计数器累加有没有漏掉,一套题全测出来了。如果你能独立、完整地写出这道题并且一次通过,那一级考试的选择题和判断题只要认真读题,基本问题不大。
还有个容易被忽略的点是编程语言。GESP一级可以选择C++或Python,官方推荐C++,因为从长远来看,后面参加GESP二级甚至更高级别考试,C++的适用范围更广,而且很多学校的信息学社团也以C++为主。但这不代表Python不行,如果你只是想在低级别阶段快速上手,Python的语法更简洁,写这类题反而更快。这道"交朋友"题两种语言都能做,我后面也会把C++和Python的实现都写出来对比一下。
需要模型API调用? 免费领10W Token,多模型网关一键接入 Claude、DeepSeek 等主流模型。
2. 解题思路拆解:为什么暴力枚举就能满分
2.1 暴力枚举的核心逻辑
拿到"交朋友"这道题,最直接的想法就是:把任意两个小朋友都组合一遍,检查他们的性格值之和是不是等于k。这是最朴素的"暴力枚举",对应的代码结构就是双层for循环。
外层循环选第一个小朋友,内层循环选第二个小朋友。这里有一个关键细节:内层循环的起点要从外层循环的下一个位置开始。举个例子,外层循环变量i从0开始,内层循环变量j就要从i+1开始。这样做的原因有两个:第一,避免自己跟自己配对;第二,保证每一对小朋友只会被访问一次。如果你让j也从0开始,那(A,B)和(B,A)就会被数两次,答案翻倍,必然出错。
这种双层循环的做法时间复杂度是O(n²),当n比较小的时候完全没问题。GESP一级题目的数据范围通常很宽松,n一般不会超过1000,甚至可能只有100到200,这种情况下O(n²)的算法实际运算量也就是几万次到几十万次,计算机瞬间就能算完,根本不构成任何性能压力。所以我经常跟学生讲,在一级阶段,别急着学那些花哨的优化技巧,先把暴力解法写对,拿满分,这才是最重要的。
2.2 数据范围分析:怎么判断用什么算法
我见过不少学生,代码能力其实还行,但一看到题目就陷入"要不要优化"的纠结里。其实判断标准特别简单:看数据范围。如果n ≤ 1000,O(n²)的暴力枚举是妥妥够用的;如果n ≤ 10⁵,那才需要考虑用哈希表这类O(n)的算法,但这是GESP二级甚至三级以上才可能出现的考点。
"交朋友"这道题作为一级样题,数据范围设计得很友善,n基本不会超过1000。这意味着你完全可以放心大胆地用双层循环。说实话,在一级考试里,你用哈希表反而可能因为概念不清而写错,最后得不偿失。先学会走路,再学跑步,编程学习尤其如此。
不过我也建议学有余力的同学了解一下优化思路:用一张记录"每个数字出现次数"的表,遍历数组的时候,每次检查目标值k减去当前值在表里出现了多少次,把次数累加进答案,然后再把当前值记入表里。这样做的时间复杂度只有O(n),代码量也不多,但需要对哈希表或者数组计数有一定的理解。如果孩子还小,这个优化可以等到备考二级的时候再学,一级把暴力版本吃透就够了。
3. 完整代码实现:C++和Python双版本详解
3.1 手把手写C++版本
我平时带学生,用的编译软件一般是Dev-C++或者Code::Blocks,这两个都是GESP考试允许使用的IDE,免费、轻量,对新手也友好。有家长问我"GESP考试里的编译软件指的是什么",其实就是指在考试环境中用来编写和运行代码的工具。下面我贴一份完整的C++代码,然后逐段说明。
cpp复制#include <iostream>
using namespace std;
int main() {
int n, k;
cin >> n >> k;
int a[1005];
for (int i = 0; i < n; i++) {
cin >> a[i];
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
if (a[i] + a[j] == k) {
ans++;
}
}
}
cout << ans << endl;
return 0;
}
这段代码的逻辑非常清晰。先读入n和k,再读入n个小朋友的性格值存进数组。数组开成1005,而不是1000,是因为保险起见多留几个位置,防止万一题目数据写得不严谨。然后定义计数器ans初始化为0。接着就是核心的双层循环,外层i从0到n-1,内层j从i+1到n-1,如果两个值加起来等于k,ans就加1。最后输出ans。
有几点要特别提醒。第一,ans一定要初始化成0,C++里如果没有初始化,变量会得到一个随机的"脏值",到时候输出结果可能会是一个莫名其妙的巨大数字,这种错误在初学者里非常常见。第二,循环边界是i < n和j < n,不能写成i <= n,因为数组下标是从0开始的,数组最后一个有效元素的下标是n-1,访问a[n]就会越界。第三,cin和cout虽然方便,但因为C++默认的输入输出同步模式稍微慢一点,如果数据量很大可以考虑加一行ios::sync_with_stdio(false),不过一级考试的数据量基本用不上这个。
3.2 Python版本与两者的差异对比
如果孩子选的是Python,代码会更简洁:
python复制n, k = map(int, input().split())
a = list(map(int, input().split()))
ans = 0
for i in range(n):
for j in range(i + 1, n):
if a[i] + a[j] == k:
ans += 1
print(ans)
Python版本的核心思路和C++一模一样,都是双层循环枚举每一对小朋友。区别在于Python的语法更简洁,for循环用range,数组用list,输入用input()配合split()和map()。对于初学者来说,Python的上手门槛确实更低,少了很多C++里容易踩的坑,比如类型声明、数组越界这些。
不过从备考角度说,我还是推荐有余力的孩子优先选择C++。原因很简单,GESP后面级别的内容,包括二级的结构体、三级以上的排序和查找,C++的配套学习资源更丰富,竞赛路径也基本围绕C++展开。如果先学Python再转C++,虽然思路是通用的,但语法习惯需要一定时间调整,反而可能拉长整体备考周期。
4. 考场实战:从读题到拿满分的全流程演练
4.1 拿到题目后先别急着写代码
我每次模拟考试都会强调一个原则:先读懂题,再动键盘。"交朋友"这道题虽然简单,但如果没有养成好的读题习惯,到了后面更复杂的题目就会吃亏。拿到题目之后,我建议按照下面的顺序来操作。
第一步,把题目完整读一遍,划出所有数字和限制条件。比如n的范围是多少,k是什么类型,性格值有没有可能为负数或者0。大多数GESP一级题目是不会出负数的,但存在可能的情况下代码也要能正确处理。第二步,在草稿纸上手算一个简单的例子。比如n=3,性格值是[1, 2, 3],k=3,那么符合条件的只有1+2=3这一对,答案是1。第三步,根据手算结果去验证你的代码逻辑,确保输出和手算一致。第四步,再测试几个边界情况,比如n=1时答案应该是0,所有性格值加起来都不等于k时答案也是0。
这套流程走下来,比闷头写代码然后反复调试要高效得多。我带的学生凡是养成这个习惯的,上考场后代码一次通过的概率高很多,考试时间也充裕得多。很多孩子不是不会写代码,而是"急性子",题目没看完就上手,结果漏条件。GESP一级总共就程序设计题几道大题的输出,一道题能不能满分,很大程度上就取决于你读题够不够仔细。
4.2 题目样例验证与错误分析
假设题目给的样例是这样的:第一行是4和5,第二行是1 2 3 4。也就是说,n=4,k=5,四个小朋友的性格值分别是1、2、3、4。哪两对加起来等于5呢?1+4=5,2+3=5,所以答案是2。
拿这个样例跑一遍我的代码:外层i=0时,j从1到3,分别计算1+2=3、1+3=4、1+4=5,命中一次;外层i=1时,j从2到3,计算2+3=5,再命中一次;外层i=2时,j从3开始,计算3+4=7,不命中。所以ans最终是2,输出正确。
这里正好可以解释一个很多新手会犯的错误:如果内层循环j不是从i+1开始,而是从0开始,那会发生什么?外层i=0时,j=0判断1+1=2,不命中;j=1判断1+2=3;j=2判断1+3=4;j=3判断1+4=5,命中;外层i=3时,j=0判断4+1=5,又命中一次。这样同一个配对(1,4)就被数了两次,最后的答案就会偏大。这就是为什么j的起点必须是i+1,而不是0。
4.3 完整的5步调试清单
不管代码看起来多么简单,交卷之前都应该做一遍检查和调试。我整理了一个适合GESP一级的调试清单,每次都让学生按照这个来:
- 是否把所有变量都初始化了?特别是计数器ans,一定要在定义时就赋值为0。
- 数组大小是否足够?记住数组下标从0开始,需要n个元素就要开至少n+5个位置。
- 循环边界是否正确?i < n还是i <= n,一个符号之差就会导致越界或者漏掉最后一个元素。
- 输入格式是否匹配?如果题目说第一行两个整数,你就不能先读一个再读一个再读一个,要严格按照格式来。
- 输出格式是否匹配?题目要求输出一个整数,那就只输出整数,不要额外加任何提示文字,比如"答案是:"这种话千万别写。
这5步检查一遍,最多两分钟,但能帮你避免大多数扣分点。我见过太多学生因为输出多了个空格或者少了换行被扣分,特别可惜。GESP的评分是严格按照输出内容来判定的,任何多余的字符都可能导致结果判错。
5. 常见错误盘点:这些坑每年都有人踩
5.1 变量未初始化导致的随机结果
这可能是我在初学孩子身上见到的最多的错误。C++中,如果你在定义变量时没有给它赋初值,这个变量会存储一个系统随机分配的"垃圾值"。当代码运行到ans++这一步时,因为ans一开始不是0,最终输出的结果就会在正确答案的基础上加上一个随机的偏移量。虽然某些编译器在调试模式下会自动把这种变量初始化为0,但考试环境下的编译器未必会这么做,所以绝对不能依赖编译器。
正确的做法是写int ans = 0;,Python里则是写了ans = 0再开始累加。这个问题虽然很小,但每年考试都有孩子因为这个丢分,而且很多孩子因为输出结果是乱码一样的数字反而更混乱,浪费大量时间排查。
5.2 重复计数问题
重复计数也是这道题超级常见的错误。正如我刚才分析的,如果内层循环的起点写错了,每一对会被统计两次,导致答案偏大。这个问题用文字解释可能有点抽象,但用具体样例跑一遍就特别直观。所以我讲题的时候一定会带着孩子手动模拟一遍循环过程,让他们亲眼看到问题出在哪里。
还有一种情况是孩子把"两个人可以交换位置"理解错了,觉得(1,4)和(4,1)也算不同的两对。实际上题目中的"一对"是无序的,本质上两个人之间的关系是双向的,计算的时候只数一次。这种思维偏差不属于编程问题,而是题目理解问题,需要多读题、多结合生活场景来理解。
5.3 边界条件考虑不周
边界条件主要包括三种情况。一种是n特别小,比如n=1,这时候没有任何"一对"存在,答案应该是0,如果代码里循环处理不当可能越界访问。另一种是n=0,虽然题目一般不会这么出,但如果出现了,代码也要能正常运行。第三种是性格值全部不满足条件,答案也应该为0。
针对这些边界情况,最好的办法就是构造测试数据去验证。把n=1、n=2、所有值都不满足、第一个就满足等情况全部测一遍,代码的正确性就有保障了。这个方法看起来繁琐,但对于考试而言非常实用。
6. 从这道题延伸出去:一级到二级的衔接准备
6.1 "交朋友"背后的算法思想进阶路线
"交朋友"这道题的暴力解法是O(n²)的双重循环,但它的优化版本——用哈希表把时间复杂度降到O(n)——其实是一道非常经典的面试/竞赛入门题。很多孩子学到这里会产生一个疑问:既然暴力解法就能得分,为什么还要学优化?
我的回答是:为了给二级考试做准备。GESP二级虽然也没有直接考哈希表,但会开始涉及更复杂的数据结构概念,比如结构体、字符串处理、多维数组。当你学到这些内容的时候,如果再回头看"交朋友"这道题,就能更深刻地理解"算法本质是空间换时间"这句话的含义。你用一个额外的计数器数组,记录每个数字之前出现过几次,就能把双重循环变成单重循环,这就是空间换时间的经典示范。
我给学有余力的孩子留过一个挑战:用C++写一个数组计数的优化版本。数组的下标范围要根据性格值的范围来定,比如性格值最大不超过1000,就可以开一个长度为2005的数组,用值作为下标。遍历的时候,先检查k-a[i]在不在计数数组里,如果在,就把它的次数加到答案里,然后更新a[i]的计数。这个思路虽然在一级考试里用不上,但对于开拓编程思维非常有帮助。
6.2 从一道题到一类题:一级模拟题的复习方法
GESP一级的题目类型其实很固定,除了"交朋友"这种枚举配对的题,还有斐波那契数列、简易计算器、字符统计、冒泡排序模拟等风格。"交朋友"学会之后,关键是要能举一反三。比如把"性格值之和等于k"改成"两个性格值相差等于k",代码的大框架完全不用动,只需要把if里的判断条件改一下。再比如把"统计对数"改成"找出最大的一对",就变成了一道求最值的题目,需要额外用一个变量维护最大值。
所以复习的时候不要只刷一道题,而是把每一道题都试着做三种变形:改条件、改目标、改数据范围。这样训练下来,对知识点的理解深度会远超刷十道同类型题目。我带的学生里,凡是平时这么练的,考场上遇到变形题基本都能轻松应对,因为核心算法和数据结构都没变,变的只是外壳。
还有一个复习方法是"限制时间练题"。GESP一级的正式考试时间大概两小时,前面的选择题和判断题会占据不少时间,留给编程题的时间其实不算特别充裕。所以在平时练习的时候,可以给自己限定每道题15分钟,模拟考场节奏。如果15分钟写不完,说明熟练度不够,需要重点复盘。这比毫无时间压力地慢慢写要有效得多,因为你最终面对的是有时间压力的考试。
7. 关于GESP备考的几点真心话
带了好几年备考班,我越来越觉得,GESP一级考的其实不是智力,而是习惯和细心。像"交朋友"这道题,考察的算法思维可以说几乎没有,就是最简单的枚举,但每年满分率依然不是百分之百。丢分的孩子,要么是没读懂题,要么是重复计数,要么是输出多了内容,要么是变量没初始化。这些问题没有任何一个是因为"不会",全都是因为"不注意"。
所以我最后再给备考的孩子和家长们几条建议。第一,刷题不是目的,吃透每一道题才是目的,宁可少刷几道,也要保证每道题都真的理解了、能独立写出来、能给别人讲明白。第二,考试时如果感觉代码写错了,不要慌,先回读一遍题目,再用测试数据手算一遍,绝大多数错误都能在5分钟内排查出来。第三,机考环境不熟悉的孩子,考前一定要用Dev-C++或者Code::Blocks多练习几次编译运行。我知道有不少孩子平时在网页版编程平台上做题,到了正式考试却找不到编译按钮,白白浪费了时间。
"交朋友"这道题,是我认为GESP一级备考中很值得反复琢磨的题目。它足够简单,适合作为第一道"独立完成"的练手题;又足够典型,涵盖了数组、循环、分支、计数四个一级核心考点。希望这篇拆解能帮各位把这道题吃透,也希望大家能把这种认真分析的思路带到其他题目上去。代码是写出来的,分数是细心换来的,祝备考顺利。
