尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
GESP一级真题解析:交朋友题目的数组计数与取余技巧
GESP一级的题目向来有个特点故事讲得越热闹代码写得越朴素。这次的“交朋友”就是典型——名字听着像社交小游戏实际考的就是取余运算、数组计数、找最大值这几样基本功。我把这道题从读题到提交完整过一遍讲透每个决策背后的理由顺便把评测时最容易翻车的那几个细节也一起聊清楚考一级的同学建议收藏。1. 题目在考什么先看懂“交朋友”背后的考点1.1 题目内容还原为了防止没参加考试的同学一头雾水我先按GESP一级一贯的命题风格把这道“交朋友”还原成下面的样子学校有 n 个同学每个同学都有一个学号正整数。老师说如果两个同学的学号个位数相同那么他们俩就是“有缘分”的朋友。现在给出 n 个同学的学号请你帮忙统计按学号的个位数 0~9 分类那一类人数最多人数是多少如果有多个类别人数并列最多输出其中个位数最小的那一个。输入第一行是一个正整数 n表示同学数量第二行是 n 个正整数表示学号。输出一行两个整数先输出个位数再输出对应的人数中间用空格隔开。我配一组样例输入 7 11 21 33 44 55 65 77 输出 1 2样例里学号 11 和 21 的个位都是 1共 2 人55 和 65 的个位都是 5也是 2 人。按照“并列最多输出较小小位数”的规则答案就是 1 和 2。这正是我见过的一级真题最喜欢出的“略有包装、本质朴素”的题型。1.2 考点一层层剥开这道题虽然包着“交朋友”的故事真正考察的点其实非常固定。借这个机会我把一级考纲里对应到这道题的知识点彻底梳理一下你会发现它几乎就是为“数组计数”量身定做的。第一是输入输出基本功。n 和 n 个整数用 cin 或 scanf 读入最后按格式输出。这是 GESP 一级最基本的考察动作看起来简单但每年都有同学因为输出顺序写反、空格多打少打而丢分。第二是运算符的理解重点就是对 10 取余。学号可能是几十、几百甚至上百万但我只关心“个位数”那就用学号 % 10。这一步本质上是考察整数运算里“余数”的概念而不是单纯背公式。第三是一维数组做计数器。个位数一共只有 0 到 9 十种情况所以可以开一个长度为 10 的数组下标就是“个位数”对应的值就是“人数”。这种“桶计数”的写法是一级循环数组最经典的考察组合。第四是找最大值以及最大值并列时下标最小的处理。这一小问看起来温柔实际上暗藏杀机如果只找“最大人数”而不记录“对应的个位数”或者并列时没按题目要求取较小值至少扣一半分。1.3 为什么这道题适合一级我见过不少同学刷题时好高骛远一上来就研究啥高深算法结果真到了考场上被最简单的取余卡住。GESP 一级的定位本来就是“入门逻辑和基础语法”所以题目不会绕太多弯。像“交朋友”这种题目知识点全是硬碰硬的一级范围内内容但故事包装得很生活化。它要检验的就是你能不能把生活中的描述翻译成代码逻辑能不能老老实实地用循环数组把问题描述出来。说白了一级题目就是拿“讲故事”来考验“翻译成代码”的能力而不是考验算法技巧。2. 解题思路从生活故事到代码逻辑的翻译过程2.1 抓住关键词“个位数相同”往取余想读题的时候第一遍念到“学号个位数相同”我脑子里就要瞬间弹出两个运算/和%。学号除以 10 的商去掉了个位而学号取 10 的余数恰恰就是个位。比如 123456123456 % 10得到 6这正是我们想分类的依据。这里我特别提醒一点有些同学会写成x / 10觉得“去掉末尾不就是个位吗”——这是完全搞反了方向。x / 10是把个位丢掉剩下的是“去掉个位之后的数”而不是个位数本身。做题时把这句话记牢想保留个位就用%想丢掉个位才用/。我监考时见过一个同学把整个程序的计数全写错了最后查了半天根源就是/和%用混。2.2 用“桶数组”存十类人数个位数只可能是 0、1、2、3、4、5、6、7、8、9正好十个分类。最简单的做法不是定义十个变量去记而是定义一个长度 10 的数组int cnt[10] {0};数组的下标天然就是 0 到 9刚好对应十类个位数。每读入一个学号 x就执行cnt[x % 10];这句话的意思可以这么理解x 的个位数如果是 5等价于往编号为 5 的“小桶”里丢了一颗球把桶里的球数加 1。后面继续读入其他学号如果又碰到一个个位为 5 的学号就继续往 5 号桶里加。整个过程跑完每个桶里的数字就是“这个个位数的人数”。这里有个特别容易被忽略的学习点为什么用数组而不是十个 if如果用十个 if 当然也能写比如if (x % 10 0) cnt0;一路写到if (x % 10 9) cnt9;但这样代码不仅又臭又长还特别容易漏掉某一种情况。数组下标和数值一一对应的特点恰好让“个位数 - 人数”这种映射变得极其自然。以后不管遇到按月份统计、按分数段统计还是按字母统计这套“桶”思想几乎可以原封不动地搬过去。2.3 找最大值时不要踩“并列”这个坑统计结束以后问题变成在十个桶里找出数字最大的那一个桶并且输出桶的下标和桶里的数字。很多人第一反应是int maxn 0; for (int i 0; i 10; i) { if (cnt[i] maxn) maxn cnt[i]; }这么写只能算出“最大人数是多少”却完全没记录“这个最大人数对应的个位数是几”。正确做法是让一个变量同时记住“最大人数”和“对应下标”。这里我推荐一个常见写法用一个ans变量存当前最合适的个位数int ans 0; for (int i 1; i 10; i) { if (cnt[i] cnt[ans]) { ans i; } }循环结束后ans就是目标个位数cnt[ans]就是最大人数。这里细心的同学会问为什么不是而是这正是处理“并列时输出最小个位数”的关键。因为 i 从小到大遍历如果是严格大于才更新那么当两个桶人数相同时早先遇到的比较小的 i 会一直保留下来如果写成后面遇到的更大个位数就会把之前的结果覆盖掉最后输出的个位数反而变成较大的那一个。一字之差全盘皆输这个细节我在第 4 节还会专门展开讲。3. 参考代码与逐行精讲3.1 完整可提交的 C 代码把上面所有思路落到代码上就是这样一份可以直接提交的参考程序#include iostream using namespace std; int cnt[10]; int main() { int n; cin n; for (int i 0; i n; i) { int x; cin x; cnt[x % 10]; } int ans 0; for (int i 1; i 10; i) { if (cnt[i] cnt[ans]) { ans i; } } cout ans cnt[ans] endl; return 0; }整个程序去掉头文件不到 30 行结构清清楚楚。但越短的代码越要小心每个细节。下面我把每个容易看漏的地方逐一拆开讲。3.2 数组初始化这道题最阴险的“隐形陷阱”代码第一眼看上去很正常但我要重点说int cnt[10];这一句。如果这一句写在main函数外面也就是作为全局变量那么 C 标准保证它会被自动初始化为 0不需要手动清零上面这份代码没有问题。但是如果有一天你把它挪到了main函数里面写成int main() { int cnt[10]; // 局部数组里面是垃圾值 // ... }那就完蛋了。局部数组不会自动清零里面装的是内存中残留的随机值。此时你执行cnt[x % 10]就是从某个不知名的初始值开始加统计结果完全错乱。而且这种错误极其隐蔽因为程序不会报错样例可能碰巧能过换一组数据就稀里哗啦。我的建议是不管数组放在哪里一律写成带初始化器的形式从根源上消灭问题int cnt[10] {0};这行代码的意思是“第一个元素初始化为 0其余元素自动补 0”。哪怕你以后把代码从全局搬到局部也不会因为初始化问题翻车。类似的开bool数组、char数组、long long数组时只要需要初始值就老老实实写 {0}或者用循环赋值不要赌编译器“恰好帮我清零”这种赌运气没有任何意义。3.3 读入阶段的解释为什么不用管学号到底多大读入的时候代码里只有一个int x; cin x;然后马上执行cnt[x % 10]。这里有人会担心如果学号是 1000000甚至更大会不会越界不会因为% 10的结果只可能是 0 到 9学号有多大都不影响取余运算已经把数值“压缩”到了我们关心的个位数上。数组下标用的是取余之后的结果而不是学号本身所以数组始终不会越界。还有一个容易忽略的输入格式问题题目说“第二行是 n 个整数”很多同学会在意这 n 个数是不是真的在同一行。从标准输入的角度看cin 读取整数时天然忽略空格和换行不管这些数是挤在一行还是分成好几行只要按顺序读入结果完全一样。所以读入部分完全不需要考虑“换行”问题一个 for 循环读 n 次即可。3.4 输出阶段题目先要个数还是先要人数输出语句cout ans cnt[ans] endl;里ans是个位数cnt[ans]是人数。这个顺序必须和题目要求完全一致。我见过不少同学统计全对结果输出时先打了人数再打个位数直接和答案格式不匹配。GESP 评测机比对的是“标准输出和你的输出是否一模一样”顺序反了必然判错。拿到题目先把输出格式在题目原文上圈出来再写代码这是所有考试通用的保命手段。3.5 时间复杂度与空间复杂度分析这段代码只有一个 for 循环读入加一个 for 循环找答案每个循环各自跑 n 次和 10 次总时间复杂度是 O(n)。空间上只开了一个长度 10 的 int 数组空间复杂度是 O(1)。这意味着即使 n 开到 100000甚至 1000000程序都能在极短的时间内跑完。GESP 一级的 n 通常不会给得太大但对于这种“一次遍历、常数空间”的解法完全不需要担心超时或超内存。这个复杂度模型也值得记在心里凡是可以边读边统计、最后只查一小段数据的问题基本都是 O(n) 解法考试时不要在简单问题上想复杂了。4. 提交前必须检查的 5 个细节代码写出来是一回事能在评测机拿到满分是另一回事。我把自己在训练和实际评测里反复踩过的坑整理成一张检查清单建议你每次交题之前都按这个顺序过一遍。第一桶数组的初始化。局部变量数组不初始化就是随机垃圾值写int cnt[10] {0};永远是最稳妥的选择。这里不单单是“能不能过”的问题还是代码习惯的问题从一开始就养成好习惯以后遇到更复杂的状态数组时才能少走弯路。第二取余别写成整除。x % 10和x / 10只差一个符号但结果天差地别。考试时间紧张时人容易手滑提交前扫一眼关键代码确认自己用的确实是取余%而且不是%n、%100这类不相关的取模。第三找最大值时用的是而不是。这个我前面说过了它是“并列取最小下标”的核心。如果你把题目改成“并列时取较大小位数”才需要把改成。做题时一定看清题目条件这个细节在样例输出里往往能看出来但如果样例恰好没触发并列情况就需要你自己额外构造一组并列数据来测试。第四检查输出顺序和格式。先个位数还是先人数中间是空格还是换行末尾要不要再加一个空格这类问题每年都有同学中招。我的办法是拿到题目先把输出描述抄在草稿纸上写成“输出x y”这样明确的形式再开始写代码能有效防止输出顺序写反。第五极端数据是否安全。n 的最小值是多少如果 n 为 1程序会不会出错我的代码里 n 为 1 时统计一个学号后找最大值依然正确。如果所有学号的个位数分布很不均匀比如全是个位 0那么cnt[0]是 n其他全是 0ans 初始为 0输出 0 和 n依然正确。顺手用这两三类数据在脑子里模拟一遍提交的时候心里会踏实很多。5. 实际评测中的常见错误与排查实录5.1 常见错误速查表我把这些年学生答疑时反复出现的问题汇总成一张表每一类我都标注了“症状”和“病因”方便你在报错时快速对照。症状 可能的病因 怎么修 ------------------------------------------------------------- 输出全是0 cnt数组是局部变量 全局定义或 {0} 答案人数少一截 用了x/10而不是x%10 改成 x%10 并列时总输较大的数 if里写成 改回严格大于 运行崩溃/越界 数组下标写成cnt[x] 改成cnt[x%10] 格式不对 先输人数后输个位数 按题目要求调序 样例过但提交0分 多个输出顺序错或少了空格 逐字比对输出描述这张表只是排错的第一步。真正要命的问题往往是“样例明明过了提交上去却是 0 分”这是评测里最常见、也最让人崩溃的情况。5.2 样例过了不代表全对一个典型的排查过程我曾经带过一个学生写完后样例输出和答案一模一样提交后却是 0 分。拿到他的代码一看问题出在数组定义成局部变量但没有初始化。样例数据碰巧让数组初始垃圾值相加的结果“歪打正着”跟正确答案一样换正式数据就彻底崩了。这类问题用样例测根本测不出来唯一的排查方式是重新读一遍自己的数组定义和初始化逻辑。另一个类似的坑是输出语句里多了或少了一个空格。评测系统会把输出结果当作一个字符串整体来比较1 2和12是完全不同的字符序列。有的同学觉得“输出里有没有空格无所谓”这个想法在编程题里是致命的。样例输出是第一手标准答案打空格时就要打成和它一模一样的样子。还有一种情况是边界条件没考虑全。比如题目说 n 的范围是 1 到 100000但有人写循环时从 i1 开始读到 in结果少读了一个数据样例一般发现不了但数据稍微大一点就出错。解决方法是养成“在草稿纸上用极小数据手动模拟一遍”的习惯比如 n1 时跑一遍n2 时跑一遍边界值永远是BUG最喜欢的藏身之处。我自己在实际做题时的排查流程是先检查数组初始化再检查取余符号然后检查循环边界最后检查输出格式。这四个地方只要都正常一道一级水平的数组计数题基本不可能再出大问题。把这个顺序记住你也能少走很多弯路。6. 变式拓展“交朋友”还能这么改6.1 变式一从统计人数改成统计对数原题问的是“人数最多的组有多少人”但如果题目改成“请你统计一共能组成多少对朋友”也就是有多少对学号的个位数相同怎么处理这时候思路要稍微转一下。设个位数为 i 的桶里有 cnt[i] 个人那么这一组内能组成的“朋友对”数量是组合数 C(cnt[i], 2)也就是cnt[i] * (cnt[i] - 1) / 2。把十组加起来就是所有朋友对的总数。long long ans 0; for (int i 0; i 10; i) { ans 1LL * cnt[i] * (cnt[i] - 1) / 2; } cout ans endl;这里有个细节为什么用long long因为 n 如果达到 100000最极端的情况是所有人都数个位相同比如全是 1那么朋友对数约等于 100000×99999÷2接近 50 亿int 完全放不下。很多同学在这里被坑过运算过程本身没错但存储类型装不下结果最后得到负数或者错误值。GESP 考试里只要涉及“计数、求和、乘积”类的答案养成“可能超范围就开 long long”的习惯准没错。6.2 变式二按后两位或其他特征分组理解了按个位分组的原理你完全可以举一反三。比如把“个位数相同”改成“末两位数相同”那只需要把x % 10换成x % 100数组长度从 10 改成 100。再比如改成“按奇偶分组”那么桶只有两格下标可以取x % 2。又比如改成“按学号的百位相同”那就先用/100去掉百位后面的数字再取 10 的余数。这一系列变化背后只有一个核心思想所谓的“分类”其实就是“把某个特征提取出来映射成数组下标”。不管是按个位、后两位、奇偶、月份还是字母本质都是同一套桶计数的思路。真题里所有的“新题”绝大多数都是这套思想的变体把这道题吃透了就等于握住了一把解一类题的钥匙。6.3 变式三用 map 或结构体的进阶思路有同学可能会问如果分类不是 0~9 这种连续整数而是字母、字符串桶数组还能用吗这时就可以引入 map 或者 unordered_map。简单说map 就是“不限制下标必须连续”的桶它能记录“任意键 - 数量”的映射。比如统计一系列单词里哪个词出现次数最多就可以用 map。#include map #include string mapstring, int mp; mp[word];不过在 GESP 一级考试里map 一般用不上因为一级题目设计时下标基本都是连续的小整数。但我建议你现在就知道它的存在这样以后看到高级写法不会陌生。更重要的是理解“数组就是一种键为连续整数的映射”这个认知会帮你把 C 的很多语法串起来到后面学 C二级、三级的 STL 时你会觉得很多东西早就见过。最后再说点实在话这道“交朋友”按出题逻辑来说就是典型的一级难度故事新考点老代码短陷阱多。我个人刷了这么多套等级考试真题最大的感受是——真正让考生失分的往往不是算法想不出来而是基础细节守不住。数组清没清、余数取没取对、输出顺序对不对这才是决定 100 分和 60 分的分水岭。建议你把这篇文章里的检查清单抄下来下次做其他题时也照着过一遍养成固定套路之后考场上的稳定性会有肉眼可见的提升。
RELATED

相关推荐

从测试脚本到质量工程:Harness与Loop双轮驱动实践

从测试脚本到质量工程:Harness与Loop双轮驱动实践

1. 先搞清楚:为什么质量团队开始讨论"工程化"这件事前阵子我帮某团队做质量评审,负责人拍着胸脯说"我们有全套自动化测试"。结果打开仓库一看,几百个脚本散落在各个模块目录里,测试数据靠手工拷贝&#xff0c…

📅 2026/10/22 5:37:07
JWT认证实战指南:原理、签名算法与安全排坑

JWT认证实战指南:原理、签名算法与安全排坑

1. 项目概述与核心价值1.1 我为什么会专门聊JWT先说说我自己的经历。做后端开发这些年,几乎每个Web项目都会遇到登录鉴权的问题。早期用Session方案,后来维护微服务拆分的项目多了,Session同步就成了麻烦事。直到某次做项目重构,技…

📅 2026/10/22 5:37:07
短剧SAAS源码实战:从架构拆解到小程序与支付分账落地

短剧SAAS源码实战:从架构拆解到小程序与支付分账落地

简介:最新版视频短剧SAAS系统源码是一套面向小程序开发与运营者的完整技术包,旨在帮助用户搭建集内容管理、视频分发与数据存储于一体的影视短剧平台。基于软件即服务模式,资源涵盖前端与后端源码、数据库结构定义及填充脚本,适合…

📅 2026/10/22 5:37:07
MORE NEWS

更多资讯

📰

SRC漏洞挖掘实战指南:从入门认知到报告撰写的完整路径

这年头只要有人问起“网络安全怎么入门”,我十有八九都会推荐先去碰一碰各大公司的SRC平台。SRC全称是Security Response Center,也就是企业安全应急响应中心,说得直白一点,就是公司主动划出自己的一部分业务资产,开放…

📰

Paperxie论文查重系统:从算法设计到工程落地的完整实践

写这篇东西的起因,是去年帮某实验室的A同学看综述稿子。他把论文丢进一个主流查重系统,总相似率看着还行,16.8%,但打开报告差点没绷住:被标红的地方全是领域标准定义和常规句式,连“综上所述”都被拎出来算…

📰

降AI痕迹工具实测:10款软件效果对比与避坑指南

这两年做内容的人,最焦虑的不是写不出来,而是写出来之后“一看就是AI写的”。尤其到了2026年,各大平台的AI内容识别模型一个比一个精,光靠“换个词”“调个语序”那套老办法已经糊弄不过去了。我花了整整一周时间,把市…

📰

MySQL多实例部署与备份恢复实战指南

1. 一台服务器上为什么要跑多个MySQL实例很多人第一次听到"多实例部署"时的反应是:一台机器装多个MySQL,是不是有点折腾?但实际运维做久了就会发现,这个需求远比想象中常见。我遇到的典型场景是:公司只有一台…

📰

TiDB 集群单机部署实战:从 playground 到 cluster 模式的完整指南

TiDB 集群这种东西,大家默认是往多台机器上铺,或者直接上云。可实际开发中,最尴尬的往往是:业务还没到需要集群的规模,但我就是要一个跟生产差不多的 TiDB 环境,用来跑联调、验证 SQL、测试新版本特性。手头…

📰

Cityengine城市规划规则库实战:CGA规则驱动三维城市建模与参数调优

简介:这份资源是面向Cityengine用户的城市规划规则库工具包,适合从事三维城市建模、景观设计及规划方案推演的设计师与学习者使用,可帮助快速扩展或定制城市生成规则,降低从零编写CGA脚本的门槛。压缩包共8个文件,约36…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬