☰
GESP一级《小杨买书》考点解析:整除与取模的正确用法
2026/9/26 8:41:06 网站建设 项目流程

上周帮一个准备GESP一级考试的孩子调试这道《小杨买书》,他写了三十行代码还没跑对,我看了一眼只说了句“你把它想复杂了”。其实这道题在GESP一级里属于标准的入门送分题,考点就三个:读懂题目、用对运算符、写对输入输出。我今天就把这道题从考点到解法,再到容易踩的坑,一次性掰开揉碎讲清楚。不管你是零基础备考生、学校的编程社团老师,还是打算带娃考级的家长,这篇应该都能直接用得上。

1. 这道题到底在考什么:GESP一级的“小杨买书”考点拆解

1.1 GESP一级是什么级别,难度如何

GESP全称是青少年编程能力等级认证,一级是这个考试体系的第一个台阶,主要面向刚开始学编程的小学和初中阶段学生。考试形式为机试,包含选择题和编程题,其中编程题是最能拉开分数的部分。GESP一级要求掌握的内容其实非常基础:变量、数据类型、输入输出、顺序结构、选择结构、循环结构,以及最简单的算术运算。说得直白一点,一级考试不会考数组、字符串、函数这些进阶内容,更不会考算法复杂度,它就是考察学生能不能把日常生活中一个简单的数量关系,用代码表达出来。

但“简单”不代表“容易得分”。我在实际辅导中观察到,很多孩子能听懂课,但一到考场就懵,原因通常不是题目难,而是读不懂题目背后的运算关系,或者对输入输出格式不够敏感。《小杨买书》恰好就是这类“读题比写代码更难”的题。它的题面会用生活化的场景包装一个非常朴素的数学问题,你需要做的是从故事中抽取出“已知什么、要求什么、用什么运算”这三件事。

1.2 “小杨买书”在GESP一级中的典型性

这道题的题目编号是B3952,对应GESP 202403(即2024年3月)一级考试。它为什么会成为一道经典题?因为它几乎把所有一级要考的基础要素都打包了:键盘输入、整数变量、算术运算、标准输出。而且和单纯考察“a+b”的题不同,“买书”这个场景天然带有包含余数的除法逻辑,这就引出整除运算和取模运算这两个非常重要的概念。

我这里先说一个最关键的版本:题目给出小杨身上带的钱数,以及一本书的单价,要求计算小杨最多能买几本书,以及买完这些书后还剩多少钱。举个例子,小杨带了20元,每本书3元,那他最多能买6本,花了18元,还剩2元。题目要求输出“6 2”。

这个版本我印象中是考场上比较常见的一种出法。还有一些变体是反过来给单价和数量求总价,或者给一个整数问能否整除,但底层逻辑都一样。我今天就以“求最多购买数和剩余金额”作为主版本展开,因为它在代码实现上有更值得讲的细节——整除和取模的配合使用。如果你在考场上遇到的是“算总价”的版本,看完这篇也能举一反三。

2. 从生活问题到程序逻辑:把“买书”翻译成代码

2.1 题目原意与输入输出要求

先把这个主版本的形式化要求完整写出来。假设输入包含两个整数,用 m 和 p 表示:m 是小杨身上的总钱数,p 是每本书的单价。输出一行,包含两个整数,第一个是最大购买数量,第二个是买完后剩余的钱数。题目保证 m、p 都是正整数,且 p 不为0。

这里要特别提醒新手:程序的输入不是“人话”,而是评测系统给出的测试数据。评测时会跑多组不同的输入,你的程序必须对每一组输入都能输出正确结果。比如评测输入是“20 3”,你的程序输出必须是“6 2”,不能多空格,不能少换行,更不能输出“小杨买了6本还剩2元”这种带文字的内容。这一点很多第一次参加机考的孩子会犯迷糊,我在后文会专门讲。

从数学上看,购买数量的公式是 购买数 = 总钱数 ÷ 单价 的整数部分;剩余金额 = 总钱数 − 购买数 × 单价。用例子验证:20 ÷ 3,商是6,余数是2,所以输出6和2。这里“商”用的是整除,“余数”用的是取模。

2.2 为什么用整除和取模:核心运算的数学含义

很多初学者不理解,为什么不能直接写 m / p。这里的关键在于编程语言里“除法”分两种。C++ 和 Python 中,如果两个操作数都是整数,C++ 的 / 执行的是整数除法,结果直接截断小数部分;而 Python 用 // 表示整除,用单个 / 会得到浮点数。这道题里书只能按“本”买,不可能买6.666本,所以必须用整除。

取模运算 %(Python 里也是 %)求的是余数,它和整除是一对搭档。你可以把“m 除以 p”想成是把 m 元钱按每份 p 元去分,整除得到“能分成多少整份”,取模得到“分完后还零出来多少钱”。生活类比一下:你手里有20颗糖,每3颗装一袋,整除就是问你“能装满几个袋子”,答案是6;取模就是问你“剩下几颗糖装不了袋”,答案是2。两者合起来才是完整的分配结果。

还有一个细节值得讲:整除和取模满足一个恒等式:m = (m / p) * p + (m % p)。也就是说,商乘以除数再加上余数,一定等于被除数。这个恒等式非常有用,当你怀疑自己的结果不对时,用这个式子手算一遍就能验错。比如 20 = 6 × 3 + 2,等式成立,所以答案正确。

2.3 数据范围与变量类型选择

GESP一级的题通常不会考特别大的数,但你还是得有类型意识。C++ 里 int 类型能表示的整数范围是大约 -21亿到21亿,对于本题通常够用。但如果将来遇到钱数或单价大到可能超过 int 范围的情况,就要用 long long,在变量名前加 long long 即可,输出格式几乎一样。Python 则完全不用操心,整数类型可以无限大,这也是很多初学者觉得 Python 更“省心”的原因。

不过“够用”不代表可以乱写。我见过不少学生把单价定义成 double 或者 float,理由是“价格可能有小数”。如果题目明确输入都是整数,这样做就会带来两个问题:一是编译器或解释器在处理浮点数除法时会产生精度误差,虽然这道题数字小可能看不出来,但养成了坏习惯;二是评测系统比较的是你的输出文本,浮点数输出可能会带出一长串小数或者科学计数法,导致格式错误。在GESP一级阶段,凡是题目说整数,就老老实实全部用整数类型。

这里再补充一个判断“要不要用浮点数”的小技巧:你只需要看题目场景中的物理量是否天然可以取小数。书的本数一定是整数,人民币金额在题目中也给了整数条件,所以整个问题里不应该出现小数。如果必须用小数,再谈浮点类型。

3. 两种语言,一套思路:C++ 与 Python 的完整实现

3.1 C++ 代码逐行拆解(含样例验证)

GESP一级考试支持C++和Python等语言,但很多学校备考主力是C++。我们先看C++写法:

#include <iostream> using namespace std; int main() { int m, p; cin >> m >> p; int count = m / p; int rest = m % p; cout << count << " " << rest << endl; return 0; }

逐行来看。#include <iostream>是引入输入输出头文件,没有这行就没法用cin和cout。using namespace std;是为了少写std::前缀,一级考试中可以这么用,能减少敲键盘的负担。int m, p;声明两个整数变量,分别接收总钱数和单价。cin >> m >> p;从键盘缓冲区读入两个整数,空格或换行都能作为分隔符,这符合评测时的常见输入格式。

int count = m / p;是核心第一句,执行的是整数除法,得到最大购买数量。int rest = m % p;是核心第二句,得到剩余金额。最后cout << count << " " << rest << endl;输出两个数,中间用一个空格隔开,末尾换行。很多评测系统只关心你输出的数据,不关心你是否输出多余的提示文字,但空格和换行必须符合题目要求。

用样例“20 3”验证:程序读入 m=20,p=3,count 计算为 6,rest 计算为 2,最终输出“6 2”。代码简洁、无歧义。在GESP的实际机考环境中,这种写法完全可以通过编译并拿到满分。

3.2 Python 代码逐行拆解(含样例验证)

Python 的写法更贴近自然语言:

m, p = map(int, input().split()) count = m // p rest = m % p print(count, rest)

第一行input().split()读取一行文本,按空白字符切分成若干部分,map(int, ...)把每一部分转成整数,再用m, p =分别赋值给两个变量。如果你还不熟悉map,也可以写成两行:

line = input().split() m = int(line[0]) p = int(line[1])

这样更好理解:先拿到两个字符串,再分别转整数。需要注意,Python 的//才是整除,单独的/得到的是浮点数。用/的话,20 / 3会得到6.666666666666667,这显然不是“最多买几本”的答案。%求余数则和C++一致。

最后print(count, rest)输出两个整数,print 默认用空格分隔并在末尾自动换行,恰好满足题目要求的输出格式。用样例验证:输入“20 3”,程序输出“6 2”。完全正确。

3.3 计算过程示例:手算验证

我再给一个非整数倍数的例子,帮助加深理解。假设输入是“100 7”,也就是小杨带了100元,书单价7元。

用整除:100 ÷ 7 的商,因为 7 × 14 = 98,7 × 15 = 105(超过100了),所以商是14。用取模:100 % 7 的结果是 100 − 98 = 2。程序输出“14 2”。手算检验:14本 × 7元 = 98元,100 − 98 = 2元,刚好一致。

再看一个刚好整除的例子:“30 5”。30 ÷ 5 = 6,30 % 5 = 0,输出“6 0”。这意味着钱刚好花完,余额为零。很多新手觉得“余数怎么可能是0”,但这恰恰是取模运算非常重要的一个功能——判断一个数能否被另一个数整除,就看余数是否为0。这个思想在后续学习“判断闰年”“判断质数”时还会反复出现。

4. 一级考试中最容易丢分的4个细节

4.1 输入输出格式不匹配

GESP是机器评测,它不会像学校的老师那样“看在你思路对的份上给几分”,输出和期望不一致就是零分。最容易出问题的有三个地方:一是多输出了提示文字,比如“请输入钱数”,这在本地运行没问题,但评测时会让答案多出非数字内容;二是数字之间的分隔符不对,题目要求空格,你却输出换行或逗号;三是末尾少换行或多换行,某些评测器对多空格多换行容忍度较高,但最好不要赌,严格按要求来。

我怎么帮学生自查呢?有一个很笨但有效的方法:把题目的样例抄下来,用手动输入的方式跑一遍程序,然后把输出结果和期望输出逐字符对比,包括空格和回车。很多考生问“我明明能算出正确答案,为什么评测是0分”,八成是格式问题。这里建议在C++里统一用cout << count << " " << rest << endl;,Python里直接用print(count, rest),这两种写法天然符合GESP常见的输出规范。

4.2 滥用浮点数导致精度隐患

这个坑我在前面提过,但值得单独拿出来说。有的学生觉得“钱嘛,当然可能有小数”,于是把变量定义成double,然后用m / p去算。C++中double / int会把 int 提升为 double 再做浮点除法,结果是 6.666...,如果你把这个浮点数直接赋给 int 变量,会发生截断变成6,好像结果也对。但这里存在两个隐患:一是浮点数在计算机内部是近似存储,当数字较大时,m / p的结果可能比真实值小一点点或大一点点,截断后就会差1;二是如果题目要求输出整数,你却可能因为某些操作输出成6.66667这种格式。所以我在带学生练习时立了一条规矩:题目说整数就用整数,代码里不允许出现double。

Python 那边,一旦用了/就是浮点数,哪怕结果是6.0,打印出来也会变成6.0,和期望输出的6不一致。有同学会在print(int(count), int(rest))里强行转回整数,倒也能救回来,但何必呢?直接用//和%,干干净净。

4.3 没有理解“评测是多组数据”

机考评测时,系统会拿多组测试数据分别运行你的程序,每组数据都独立测试,你的程序需要能对任意合法输入都给出正确答案。有的学生写代码时为了验证方便,把变量在程序里写死,比如int m = 20;,然后直接输出。这在本地运行的确输出了“6 2”,但评测系统一换输入就废了。所以程序的核心一定是“从标准输入读取数据”,而不是把数据写在代码里。

这个理解上的误差还会导致另一个问题:有的学生把一道题写成“死循环”,反复读输入直到结束。GESP一级题目通常只有一组输入,或固定格式的两三个数,不需要while(cin >> m >> p)这种写法。虽然这种写法也能应付单组输入,但容易让新手混淆。碰到一级题目,明确有几组数据就写几个cin或input(),不要让程序陷入等待输入的死循环。

4.4 本地环境与评测环境的差异

不少学生平时用的是Dev-C++、Visual Studio或者在线IDE,考场上却可能换一个编译环境,于是遭遇奇奇怪怪的问题。最常见的差异是:旧版编译器不支持某些新特性,比如long long在某些古老编译器里需要用__int64,但现在GESP的考纲范围里,正规的新版编译器都能直接支持long long,不用过度担心。还有考生在本地运行两个程序窗口,误以为程序卡死了,实际上是评测机房没有图形界面,只有命令行,所以不要依赖“暂停窗口”等操作。

这里给一个实用建议:备考期间就养成“标准输入输出”的编程习惯,不要用system("pause"),不要写死路径,不要在代码里加与题目无关的输出。这样到了任何环境都能平滑切换。

5. 从“小杨买书”延伸到更多一级题型:备考路线建议

5.1 一个知识点对应一类题

《小杨买书》背后对应的是一个能力点:把生活中的除法问题分解为“商和余数”,并用整除和取模表达出来。GESP一级还有很多同类型的题,比如“分糖果”:n个糖果分给k个小朋友,每人几颗剩几颗;“坐船”:m个人每条船坐k人,需要几条船,这个要考的可能是商加1的判断;“水费计算”:用水量分段计费,考察的是条件分支加四则运算。

同一种能力会以不同场景出现,这就是为什么我建议你不要只背题目答案,而是总结“看到这个场景该想到什么运算”。买书、分糖、排队、坐车,本质上都是“整除与余数”的变体。如果你能把这类题吃透,一级考试里很大一部分送分题就稳了。反过来,如果你只背住《小杨买书》的输出格式,考场上换一件“衣服”你可能就认不出来了。

5.2 刷题与自测规划

距离考试还有两三个月时,我建议每周安排两次完整的机考模拟,每次控制在45分钟左右,只做历年真题。做题的时候一定要开着计时器,因为很多考生不是不会做,而是前面磨蹭太久,最后没时间敲代码。一级编程题一般数量不多,但每题都要经历“读题、建模、写码、检查”四个步骤。对一道题,最好先花两三分钟手动在草稿纸上算一遍样例,确保自己理解了数量关系,再开始写代码。

自测时不要只跑样例,要自己构造边界数据。比如《小杨买书》这道题,你可以测试“钱数等于单价”的情况,比如输入“5 5”,期望输出“1 0”;还可以测试“钱数小于单价”,比如输入“3 5”,此时商为0,余数为3,输出“0 3”。这种边界测试能帮你验证代码在极端情况下是否正确。

5.3 一级高频错误速查表

我带过的学生中,一级丢分最多的原因集中在以下几条:

  • 输出时多了提示文字,比如cout << "请输入"。
  • C++中cin >> m >> p;漏了>>,或者末尾忘了分号。
  • Python中把//写成/,导致结果为浮点数。
  • 变量命名和题目含义顺序搞混,比如把单价赋值给钱数。
  • 用了未初始化的变量,C++里如果不给变量赋初值,可能拿到一个随机值。

这里特别强调一下变量初始化。C++中定义变量int m, p;后立刻cin读入是没问题的,但如果某个分支条件下没有读入就使用变量,行为就未定义了。一级考试虽然很少考到那么刁钻的情况,但你可以在定义时顺手给个初值int m = 0, p = 0;,这是好习惯,能省去很多调试时间。

我再分享一个个人经验:平时练习时,拿到题目第一件事不是在编辑器里敲代码,而是拿出一支笔,在草稿纸上写出“输入是什么,输出是什么,关系式是什么”三句话。《小杨买书》对应的三句话就是:输入是钱数和单价,输出是数量和余额,关系式是数量等于钱数整除单价、余额等于钱数取模单价。想清楚这三句话,代码其实十秒钟就能写完。很多题目看起来绕,只是因为你跳过“建模”直接“上手”,觉得题目和生活背景太像,反而被带偏了。这也正是GESP这类等级考试设计的初衷:编程语言只是工具,真正考的是你把生活中的问题抽象成计算规则的能力。把这道“小杨买书”彻底吃透,你离顺利通过一级就更近了一步。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询