最近在带几个学生准备GESP一级考试刷到2023年9月这套真题的时候B3863这道“买文具”让我印象挺深。可能有人会说这不就是一道最基础的计算题吗有什么好讲的但恰恰是这种看起来“过于简单”的题最能暴露初学者在输入输出、变量类型、运算顺序上的问题。如果你正准备考一级或者刚开始接触编程认真吃透这道题比你盲目刷十道难题更有价值。我自己的经验是每次带学生第一节课不会急着讲花哨的算法而是先让他们把这类“读完题就能列算式”的题写到滴水不漏。因为编程这件事语法是壳能把现实问题翻译成计算机能理解的步骤才是真正的内核。“买文具”就是这样一个绝佳的练习素材它场景贴近生活逻辑直白却能串起好多基础知识点。下面我把这道题的拆解思路、双语言代码、坑点和备考方法一次说完。1. 这道题究竟在考什么1.1 题目大意看清了吗这道题的常规版本是这样某同学去文具店买文具店里卖笔记本、铅笔、橡皮三种商品。输入三行每行两个整数分别表示对应文具的单价和购买数量要求计算总价并输出。如果题面在具体文具种类或输入格式上有细微调整解题逻辑完全一样核心始终是“单价乘以数量再求和”。我第一次让学生做的时候好几个人读题太快以为只算一种文具的钱输出的时候直接漏掉了后面的输入。这其实不是编程能力问题而是读题的耐心问题。竞赛题的第一关从来不是写代码而是读懂题目到底要你干什么。我的建议是拿到题先别碰键盘至少把题面读两遍第一遍通读第二遍圈出所有数字和单位。很多所谓“马虎”丢的分根源都是这一步没做到位。从题面看输入包含三组数据每组是“单价、数量”输出的就是一个整数总价。如果觉得自己没看清题我教你一个最笨但最有效的办法把输入样例手算一遍。比如笔记本3元买2本、铅笔2元买5支、橡皮1元买3块先用手算出总价19再去看输出样例是什么。对上了说明你的理解没问题对不上赶紧回头重新读题。这个习惯我从学编程一直用到现在哪怕刷高阶题也一样管用。1.2 一级考试到底想考察什么拿到一道真题不要只看代码量还要看它背后的考点。GESP一级的考试范围主要覆盖变量定义、基本数据类型、输入输出、算术运算、顺序结构、简单的条件判断和循环。这道“买文具”题最核心的知识点就三个变量能用合适的变量类型存储整数数据输入输出能正确读取键盘输入、按格式打印结果算术运算能写出单价乘以数量的表达式并累加说实话这三个知识点单独拆开都不难但放在同一道题里就形成了一道检验基础的“组合题”。一级就是要把这种组合练到条件反射的程度。你看到“买文具”脑子里应该立刻蹦出两件事第一要定义多少个变量第二最终输出的是整数还是要考虑小数。这两个问题想清楚代码的大框就出来了。另外这道题还隐藏了一个容易被忽略的考点数据的组织方式。三行输入看起来是分开的但从程序处理的角度它们是一组一组的“单价、数量”对。能不能从题面里抽象出这种结构决定了你后面学数组、学结构体时会不会吃力。所以别小看一级题它是在帮你建立初始的“数据结构感觉”。就像学写字要先练横平竖直程序里的每一个输入输出动作都是在给将来的复杂逻辑打地基。1.3 为什么说这是必拿分的基础题在考试里这类题通常放在编程题靠前的位置分值就是给认真准备的人送的。我见过不少学生考完出来说“哎呀最后一题没写出来但第一题应该没问题”结果分数出来不是那么回事。问题就出在越简单越容易掉以轻心。尤其这种计算题很多人觉得“不就是乘法吗”于是变量名乱写、输入顺序搞反、输出多了提示文字各种低级错误全跑出来了。根据我的经验“买文具”这道题的得分率并不像想象中那么高。原因无非是这几个输入处理出错、变量名写错、输出格式不对甚至有些同学直接在草稿纸上排算式代码却写得七零八落。所以我的建议是这种题不但要做对还要做得“稳”。什么叫稳就是同一个代码今天写是对的明天考试写也是对的本地运行对提交到评测系统也对。要达到这个程度靠的不是考前临时抱佛脚而是平时对每一个基础动作都较真。把这种必拿分的题稳稳收进口袋你在考场上的心态会完全不一样后面的难题也能沉下心去思考。2. 从生活问题到代码逻辑解题思路拆解2.1 读题四步法找输入、找输出、找计算、找边界我一般会建议初学者用“读题四步法”来处理这类简单题步骤固定下来以后读题就不会丢三落四。这个方法不只是针对这一道题几乎所有入门级题目都能套进去。第一步找输入。题目说“输入三行每行两个整数”那你就要明确程序要从标准输入读6个整数。读入的顺序是谁先谁后必须和题面完全一致。很多低级错误就出现在这里你以为先读单价结果题面是先给数量。一个稳妥的技巧是在草稿纸上把输入样例抄一遍然后在每个数字下面标出它对应的变量名写代码时对照着来。第二步找输出。题目要求“输出一个整数表示总价”那你就要知道输出应该是一行、一个数字、末尾有换行。是整数就不要输出小数是一个数字就不要输出多余提示文字。评测系统是按标准输出逐字符比对的多一个空格、少一个换行都可能导致程序被判错。第三步找计算。这题的计算是“单价乘以数量”三种文具分别算完再求和。把算式写出来总价 笔记本单价 × 笔记本数量 铅笔单价 × 铅笔数量 橡皮单价 × 橡皮数量。能列出这个算式代码就完成了一半。列算式的时候最好把每一步的中间结果也写出来这样写代码时你能随时对照检查。第四步找边界。一级题通常不考特别刁钻的边界但你要留意数据范围。比如单价和数量是不是正整数、有没有可能超过int的范围。养成读数据范围的习惯是从一级开始就必须训练的意识。后面到了二三级输入数据里经常藏着陷阱比如负数和极大值一级就养成这个意识会省很多事。2.2 总价计算的两种实现思路面对“多组单价、数量求和”这样的问题基础阶段有两类写法。第一种是把所有输入读进来用一条表达式算完。比如读完6个整数以后直接写 total price1 * count1 price2 * count2 price3 * count3。这种写法直观和算式一一对应适合数据组数确定、数量少的场景。优点是逻辑清晰缺点是如果文具种类变成100种表达式会写到怀疑人生。第二种是用一个累加变量循环读入每一组数据边读边加。也就是先设置 total 0然后每次读到一组单价和数量就执行 total total 单价 × 数量。这种写法更接近真实生产代码的习惯因为现实中的输入行数往往是可变的不可能在代码里提前写死。虽然一级考试还未必要求用循环但我建议有心挑战满分的学生把这种写法也练一练。对于这道题两种方法都能过。但在学习阶段我建议你先把第一种写熟练再切换成第二种。为什么因为第一种能帮你验证自己对算式的理解第二种则帮你建立“累加器”这个重要编程思想。累加思想后面会在求和、计数、统计这些题目里反复出现早一点接触后面学循环时会顺畅很多。实际上很多二级题目就是在“买文具”这个模型上不断加料先打牢底子后面就是水到渠成的事。2.3 伪代码把思路变成步骤写代码之前先在纸上写伪代码是我特别推荐初学者养成的习惯。尤其考试的时候思路容易乱伪代码就是你的定心丸。伪代码不要求语法规范只要你自己能看懂就行它的作用是逼你把思路往前推一步。以累加器的思路为例伪代码可以写成这样total 0 重复3次 读入 price, count total total price * count 输出 total就这么几行。写完后你会发现代码翻译工作变得机械而简单。很多学生跳过了这一步直接上手写代码结果往往是这里少个变量、那里多个符号越改越乱。伪代码的价值在于它把“想”和“写”这两件事分开了先在脑子里把方案想清楚再进入语法层面去落实。有人觉得写伪代码浪费时间我觉得恰恰相反。这道题简单可能十分钟就写完代码了伪代码只占两分钟。但等你学到二三级面对带条件、带循环、甚至带嵌套的题目伪代码能帮你节省的远远不止二十分钟。我见过太多学生在考场上改了又改最后发现思路起点就是错的如果先写几行伪代码完全可以避免这种惨案。3. 双语言实现C 与 Python 逐行拆解3.1 C 写法与常见细节GESP一级考试支持C和Python两种语言我周围的学生大部分选的是C毕竟后面想走竞赛路线的话C是绕不开的。先看C的完整解法#include iostream using namespace std; int main() { int price1, count1; int price2, count2; int price3, count3; cin price1 count1; cin price2 count2; cin price3 count3; int total price1 * count1 price2 * count2 price3 * count3; cout total endl; return 0; }我来逐段解释。第一行的#include iostream是为了使用输入输出流using namespace std;让cin和cout可以直接使用不用写成std::cin。对一级来说这两行直接背下来没问题但最好知道它们是在干什么。main函数是程序入口C程序从main的第一条语句开始执行最后return 0;表示正常结束。int用来声明整数变量。这里的变量名我用的是price1、count1这种带编号的命名方式用意是让代码读起来一目了然第一个文具的单价是多少、数量是多少。新手容易犯的错误是变量名乱取比如a、b、c、d、e、f写的时候确实快但一旦出错回头查代码时会非常痛苦。代码是写给人看的计算机不在乎变量名但你自己在乎。int total price1 * count1 price2 * count2 price3 * count3;这一行是整个程序的核心。注意乘法运算符*的优先级高于加法所以这个表达式会先算三个乘积再相加不需要额外加括号。如果你不确定优先级可以用括号明确一下写上(price1 * count1) (price2 * count2) (price3 * count3)也完全没问题代码只要能正确表达意图美观是次要的。最后cout total endl;输出结果并换行。endl是换行在评测系统里通常要求输出后换行所以别省。还有一个细节理论上变量可以在用到的时候再定义所以你也可以把int total ...这句话放在最后写。C对变量定义位置的要求不严格但建议养成“用之前定义、定义后尽快使用”的习惯减少变量作用域带来的麻烦。3.2 Python 写法与简洁之道如果你选Python代码可以更短。先看最直接的版本price1, count1, price2, count2, price3, count3 map(int, input().split()) total price1 * count1 price2 * count2 price3 * count3 print(total)这种写法靠input().split()把一行输入按空格拆成多个字符串再用map(int, ...)一次性转换成整数最后用多个变量接住。这个“一行代码读入多个整数”的写法在Python里非常常用建议熟练掌握。很多初学者会疑惑为什么input()返回的是字符串而map(int, ...)能直接转成整数其实map相当于对每个元素执行一次int()转换最后得到一组整数。再给一个用循环的版本更接近前面说的累加器思想total 0 for _ in range(3): price, count map(int, input().split()) total price * count print(total)这里的total price * count是total total price * count的简写Python里这类复合赋值运算符很常见。_是循环变量的占位符表示我们并不关心当前是第几次循环只需要循环三次就够了。这个循环版本的泛化能力更强如果题目改成“输入n行”只要把range(3)改成range(n)就行。Python的优点是语法灵活但也要提醒一句越灵活越容易写出“看起来对但提交就错”的代码。比如有人会写成price, count input().split()而忘记转成整数结果单价和数量都是字符串字符串乘法在Python语法上是合法的比如3 * 2得到33这种错特别隐蔽。所以初学者用Python反而要更小心地确认变量类型。3.3 样例验证与功能扩展拿到代码以后一定要用一个自己构造的样例去测试不要只依赖题目给的样例。比如我习惯用这组数据3 2 2 5 1 3按我的理解总价是3×2 2×5 1×3 19。把代码跑一遍如果输出是19说明主流程是对的。然后我还会再测一组极端数据比如单价是1、数量是1保证计算结果是1而不是别的怪数。组数少的情况下这一步很快但能帮你拦住大部分低级错误。这道题还可以往两个方向扩展用来练习变通能力。一个是加折扣比如笔记本买5本以上打八折这就需要在累加前用条件判断去修改单价或总价考查的是分支结构。另一个是不知道具体几行数据需要一直读到文件末尾C里用while (cin price count)Python里用while True加异常处理。这两个扩展都不难但能帮你把一个知识点玩出花样比死记模板强得多。就以折扣为例C版本会写成这样if (count1 5) { total price1 * count1 * 0.8; } else { total price1 * count1; }注意这里出现了小数前面用int就不合适了可能得用double同时输出格式也要调整。这种“从一个基础题长出一个新考点”的练习方式比反复做同类型题有效得多。4. 新手最容易踩的坑与排查方法4.1 变量相关类型范围、初始化、命名先讲一个我在批改代码时经常看到的错把累加变量写成了int total;但不赋初值。在C里一个未初始化的局部变量里面存的是一个不确定值如果后面直接用它做累加结果完全不可预测。所以定义累加变量时一定要顺手写上 0。这个习惯在我见过的所有编程竞赛选手里都是标配哪怕不是累加变量任何变量在第一次使用前都应该明确知道它的值是什么。另一个是数据范围的问题。这道题如果单价和数量都不大int完全够用。但假如某道扩展题里单价能到10万、数量能到10万单个乘积就是10的10次方这时候int就装不下了需要用long long。我的建议是养成读题时顺手估算数据范围的习惯别等到提交发现“答案错误”才反应过来。32位int的上限大约是21亿任何一个计算过程中的中间值超过它就要换更大的类型。变量命名也很值得说。直接用a1、b1不是不能过但一旦程序出错你盯着a1和a2很难看出问题。我会用price1、count1这种语义化命名虽然多敲几个字母但调试时的幸福感提升是实打实的。尤其考试时要检查代码一个好名字能让你快速定位到出错的那一行。4.2 输入输出相关格式、顺序、换行输入输出是最容易被忽略、又最容易出问题的地方。第一个坑是读取顺序。如果题面先说“然后输入数量”你就得按那个顺序来不能自己想当然地先读单价。第二个坑是输出提示。初学者喜欢在cout里加一句 “答案是”这在本地跑没问题但评测系统是按标准输出逐字符比对的多一个字就算错误。所以竞赛代码里输出必须严格遵守题面要求不能加任何多余内容。第三个坑是换行。有些题目要求输出后换行有些没写你也要默认加换行。大多数评测系统对换行并不敏感但养成cout total endl;的习惯可以减少意外。举个我踩过的例子有次帮学生调代码他用Cprintf输出格式串里漏了\n样例过了但提交到系统里因为多组数据连在一起而错误。从那以后我就特别强调printf和cout的换行必须和题面一致同样的道理也适用于Python的print它默认带换行所以不会有这个问题。4.3 样例过了但提交报错WA 排查思路本地样例能过提交上去却是“答案错误”WA这是初学者最困惑的时刻。我通常按顺序排查先看输入是否完全按照题面读取再看算法逻辑是否和算式一致最后用极端数据测试。很多时候问题不在思路而在一个不起眼的细节上。对于这道题我会重点检查乘法写没写错。真有学生把*写成或者把三个组的数据搞混。最直接的方法是用紧密相关的两套数据分别测试。比如一组让三种文具单价数量全相同另一组让某个数量为0看输出是否符合手算结果。第一组能检验累加逻辑第二组能检验乘法表达式里有没有遗漏项。如果还找不到问题我建议把代码打印出来逐行在纸上模拟一遍运行把每个变量的值标出来。这个方法虽然原始但对初学者排查问题极其有效。我遇过不少案例学生自己纸上跑一遍就发现问题了根本不需要我来指点。说白了会查错是比会写代码更重要的能力这也是竞赛训练的一部分。记住一个原则计算机一定是对的出错的只可能是你对题面或语法的理解。4.4 常见问题速查表把这道题相关的坑整理成一张表方便你对照检查错误症状可能原因解决方法编译报错变量未定义变量名拼写不一致检查每个变量名是否完全相同输出结果是一大串数字字符串参与乘法Python里忘记int()转换输出结果比预期大很多乘法写成加法或变量复用核对total的累加表达式本地正常、提交全错输出多了提示文字删除所有多余输出结果对但格式错少换行或多了空格检查endl和输出格式数据一大就溢出超出int范围改用long long或更大类型这张表不只适用于“买文具”这一道题很多基础题的错误类型都是共通的。你可以在自己刷题时继续往里面补充慢慢形成一份属于自己的避坑手册。遇到新错误就记录下来放假前翻一翻效果比考前临时抱佛脚好得多。5. 从这道题出发GESP 一级备考经验5.1 刷题顺序与心态一级备考最大的误区是贪难。有的学生刚学会循环就跑去刷二级、三级的题结果被虐得体无完肤回头连基础题都不愿意做了。我给出的建议其实很朴素先确保所有一级真题都能不看资料写出来再往上走。像“买文具”这种题你至少要能闭着眼在五分钟内写完并保证一次通过才算真正过关。刷题顺序上我一般推荐按“输入输出计算 - 条件判断 - 循环 - 综合应用”的顺序推进。每一步都把上一轮的基础动作练熟再进入下一个知识点。写代码和健身有点像动作不到位就加重很容易受伤。这里说的受伤就是自信心受挫。一个学生如果连续三次卡在同一类简单题上很容易产生“我是不是不适合学编程”的错觉其实只是基本功没跟上。心态上别小看简单题带来的正反馈。一道题一次通过比做十道难题然后全错要有用得多。尤其对刚接触编程的同学每一次“提交通过”都在强化一个观念我是能把事情做对的人。这个观念会在后面支撑你跨过很多坎。考试的时候也一样先把稳拿的题做对心态稳了再回头啃难题成功率会高很多。5.2 真题复盘的正确姿势复盘比刷题更重要这句话我反复给学生强调。做完一道题至少问自己三个问题我的思路和标准解法是否一致有没有可以更简洁的写法我在哪个环节犹豫了、卡住了这三个问题比单纯把代码抄一遍有用得多。针对“买文具”这样的简单题复盘的重点不是算法而是基础动作有没有变形。比如输入输出是不是一遍写对变量命名是不是清晰有没有在细节上返工。如果一道简单题你花了二十分钟那问题不在题而在某个基础动作不够熟练这时候就要针对那个动作做专项训练。我见过不少学生题目是写对了但中间反复删改了很多次这种“侥幸过关”在考场上很难复制。我常用的办法是给学生出三道同类型的变式题比如把文具换成水果、把三种商品换成两种逼他们在不同场景下用同一套逻辑快速解题。这个过程训练的不是记忆而是把核心模式抽象出来的能力。刷题数量固然重要但每一题都嚼透效果会好得多。真题就那么多你不把每一道嚼碎刷十套试卷也可能只是原地踏步。5.3 一级到二级的衔接建议过了“买文具”这一关接下来要面对的是二级考试里的分支嵌套、循环进阶和简单数组。这些内容听起来多但你会发现它们全是建立在一级基础之上的。变量用得不熟二级的数组就容易越界输入输出不熟练二级的字符串处理就会手忙脚乱连累加器都没形成肌肉记忆二级的求和类题目会更痛苦。所以我常说一级的简单题不是终点而是一个地基工程。你在“买文具”上付出的每一点细心都会在未来某道更复杂的题上得到回报。比如当你学到数组时你可能想起来原来三种文具的单价和数量用两个数组存起来再遍历求和比写三个单独的变量更优雅。这个顿悟恰恰是从这道一级题出发的。备考节奏上我个人建议二级不要急着报先做几套二级真题感受一下难度能稳定拿到及格分再考虑。毕竟考试是按级别递进的跳级备考往往得不偿失。一级的知识点就像搭积木的底座底座不稳往上堆再多的积木也会塌。把“买文具”这类题吃透后面的路会顺畅很多。写到这里我最后再说一点实操中的体会。这道“买文具”我会让每个学生至少写三遍第一遍看着讲解写第二遍自己独立写第三遍过两天再写一遍。三遍下来基础动作基本就固化住了。有人觉得重复没意义但编程能力的提升恰恰就是在这种看似枯燥的重复里发生的。如果你正在备考不妨也试试这个方法把最基础的题写到“条件反射”考试时你自然会发现紧张感少了一大半。