第9章 一级必背编程模板(编程题通关)
本章把 GESP C++ 一级(2023–2025 全部公开机试真题 + 2026 高频押题)按题型归纳成 12 个必背代码模板。每个模板都给出可直接提交的完整程序(C++17、4 空格缩进、关键行带注释),配上大白话讲解和易错警告。背熟这 12 个模板,一级编程题(2 道 ×25 分 = 50 分)基本稳过。
本工作区未安装 C++ 编译器(已确认无 g++/clang++/cl),所有代码为人工逐行核对 + 手算样例验证,未在机子上真实编译运行。请用 Dev-C++ 5.11(GESP 官方指定环境) 实地编译自测后再放心背。真题来源已在各模板标注(博客园 kkman2000 汇总、ACGO 题单、ACGO 2026 押题)。
9.1 一级编程题套路总览
一级编程题逻辑直来直去,按考点只分五类(见上图):
| 类别 | 出现频率 | 代表真题(洛谷/B 编号) |
|---|---|---|
| ① 基础计算与整除 | ★★★★★ | 长方形面积 B3850、小杨买书 B3952、温度转换 B4062、图书馆里的老鼠 B4257 |
| ② 时间日期换算 | ★★★★ | 当天的第几秒 B3847、休息时间 B4033、小杨的考试 B3921 |
| ③ 数字性质判断 | ★★★ | 找因数 B3953、立方数 B4034、美丽数字 B4035、闰年求和 B3846 |
| ④ 循环累加求和 | ★★★★ | 累计相加 B3862、金字塔 B4047、小明的幸运数 B3902 |
| ⑤ 条件逻辑与最值 | ★★★ | 商店折扣 B4046、假期阅读 B4044、小杨的爱心快递 B4445 |
- 所有输入
n ≤ 10000,暴力枚举完全可行,不用想高级算法(O(n²)也能过)。 - 语法结构是固定的三件套:输入
cin/scanf→ 处理(分支/循环)→ 输出cout/printf。 - 一级不考数组、字符串、函数、指针,所以下面模板全部用最基础写法,方便你硬背。
9.2 模板 1:标准程序骨架(趁手模板)
每道题都从这套骨架开始,只改中间“处理部分”。
#include <iostream>
using namespace std;
int main() {
// 1. 定义变量
// 2. 读入:cin >> a >> b;
// 3. 处理:计算 / 分支 / 循环
// 4. 输出:cout << ans << endl;
return 0;
}
// 用 scanf / printf 的等价写法(一级两者都接受)
#include <cstdio>
int main() {
int a, b;
scanf("%d %d", &a, &b); // 注意变量前加 &
printf("%d\n", a + b);
return 0;
}
- 漏写
using namespace std;(用cin/cout时必须写)。 scanf读入时变量前一定要加&,否则编译/运行出错。main函数最后的return 0;一级不扣分,但写上更稳。
9.3 模板 2:求最大 / 最小值(三数比大小)
真题:小杨的爱心快递 B4445(多条件分支 + 取最小值)、值日 B4045。
#include <iostream>
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
int m = a; // 先假设 a 最大
if (b > m) m = b; // 谁更大就更新 m
if (c > m) m = c;
cout << m << endl; // m 就是最大值
return 0;
}
“打擂台法”:先让 a 当擂主,后面每个数来挑战,比擂主大就上位。最小值把 > 改成 < 即可。
求最大值初始值要设成“很小”(如第一个数);求最小值初始值要设成“很大”(如第一个数),别把 m 初始化成 0 再去求最小值(会出错)。
9.4 模板 3:整除与取余(小杨买书类)
真题:小杨买书 B3952(书 13 元,零花钱 m,求最多买几本 + 剩多少)、小杨购物 B4034(成对买 A、B)、图书馆里的老鼠 B4257。
#include <iostream>
using namespace std;
int main() {
int m; // 零花钱
cin >> m;
cout << m / 13 << endl; // 整除:最多买几本
cout << m % 13 << endl; // 取余:剩下多少钱
return 0;
}
成对购买(小杨购物):A 单价 a、B 单价 b,钱 n,求能买几对:
#include <iostream>
using namespace std;
int main() {
int a, b, n;
cin >> a >> b >> n;
cout << n / (a + b) << endl; // 一对的成本是 a+b
return 0;
}
5 / 2 = 2(整数除法,直接砍掉小数),不是 2.5!
需要小数结果时必须写成 5.0 / 2 或 5 / 2.0。买书/找零这类题本来就是整数,用 / 和 % 才对。
9.5 模板 4:闰年判断(分支经典)
真题:闰年求和 B3846(样题,闰年判断 + 循环累加)。
#include <iostream>
using namespace std;
int main() {
int y;
cin >> y;
// 闰年:能被4整除且不能被100整除,或能被400整除
if ((y % 4 == 0 && y % 100 != 0) || (y % 400 == 0))
cout << "yes" << endl;
else
cout << "no" << endl;
return 0;
}
两个条件“或”起来:① 普通闰年(4 的倍数但不是 100 的倍数);② 世纪闰年(400 的倍数,如 2000 年是闰年,1900 年不是)。
9.6 模板 5:时间换算(统一为秒)
真题:当天的第几秒 B3847(样题)、休息时间 B4033、时间规划 B3861。
思路:把“时:分:秒”全部换算成总秒数做加减,再还原回去。
#include <iostream>
using namespace std;
int main() {
int h, m, s, k; // 起始时分秒 + 经过的秒数
cin >> h >> m >> s >> k;
int t = (h * 3600 + m * 60 + s + k) % 86400; // %86400 防止跨天
cout << t / 3600 << " " // 小时
<< (t % 3600) / 60 << " " // 分钟
<< t % 60 << endl; // 秒
return 0;
}
- 还原时用:时 = 总秒 / 3600,分 = (总秒 % 3600) / 60,秒 = 总秒 % 60,三个式子别写混。
- 若题目明确“不会跨天”,可不加
% 86400;加上更保险。 - 输出格式注意题目要的空格还是换行,严格照样例。
9.7 模板 6:星期推算(模运算)
真题:小杨的考试 B3921(今天星期 x,再过 n 天是星期几,0 表示星期日)。
#include <iostream>
using namespace std;
int main() {
int x, n; // x: 1=周一 ... 7=周日
cin >> x >> n;
// 先把 1..7 折算到 0(日)..6(六),再加 n 取模
int ans = (x % 7 + n) % 7;
cout << ans << endl; // 0 表示星期日
return 0;
}
二手资料常给 (x-1+n)%7,但 n=0 时会把“周一”算成“周日”,是错的。
正确做法:x%7 把 7(周日)→0、16 保持不变,再加 6=周一~周六,手算验证无误。n 取模,结果 0=周日、1
9.8 模板 7:累加求和(1 到 n 的和)
真题:累计相加 B3862、ACGO 押题 1(输入 n,输出 1 到 n 所有整数之和)。
#include <iostream>
using namespace std;
int main() {
int n, sum = 0; // 累加变量一定要初始化成 0!
cin >> n;
for (int i = 1; i <= n; i++) {
sum += i; // 等价于 sum = sum + i;
}
cout << sum << endl; // 样例:输入 10 → 输出 55
return 0;
}
进阶:公式法 sum = n * (n + 1) / 2(一句替代循环,更快更稳):
// 直接输出,避免循环写错
cout << n * (long long)(n + 1) / 2 << endl;
sum必须= 0初始化,写成int sum;(未初始化)会得到垃圾值。- 数据较大时用
long long,例如long long sum = 0;(防溢出)。
9.9 模板 8:枚举与计数(找因数 / 美丽数字 / 小明幸运数)
真题:找因数 B3953(输出 n 全部因数)、美丽数字 B4035(倍数 + 逻辑判断)、小明的幸运数 B3902(循环计数)。
#include <iostream>
using namespace std;
int main() {
int n, cnt = 0; // cnt 用于计数
cin >> n;
for (int i = 1; i <= n; i++) {
if (n % i == 0) { // i 能整除 n → i 是因数
cout << i << endl;
cnt++; // 顺便统计因数个数
}
}
// cout << cnt << endl; // 如需个数再输出
return 0;
}
优化写法(只枚举到 ,一级可不讲但知道更好):
for (int i = 1; i * i <= n; i++) { // i*i<=n 比 i<=n 快很多
if (n % i == 0) cout << i << endl;
}
“枚举法”就是让 i 从 1 数到 n,挨个问“你能整除 n 吗?”能就记下来。一级 n 很小,直接 i <= n 最稳,不用优化。
9.10 模板 9:数位分离与数字反转
真题:数字替换 BW71、各类数位操作题(取个位/十位、判断回文、反转数字)。
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int rev = 0; // 存放反转后的数
while (n > 0) {
int d = n % 10; // 取出个位
rev = rev * 10 + d; // 拼到反转数末尾
n = n / 10; // 砍掉个位
}
cout << rev << endl; // 1234 → 4321
return 0;
}
n % 10取个位,n / 10去个位,二者配合循环就能拆完整个数。- 反转时
rev = rev * 10 + d是“整体左移一位再补个位”,别写成rev = d。 - 若
n = 0需要单独处理(while 不进循环),按题目要求补if (n == 0) cout << 0;。
9.11 模板 10:浮点与最值(温度转换 / 商店折扣)
真题:温度转换 B4062(华氏→摄氏,浮点 + 分支)、商店折扣 B4046(满减 vs 打折取更优)。
温度转换(华氏 f → 摄氏 ):
#include <iostream>
#include <iomanip> // 用于控制小数位数
using namespace std;
int main() {
int f;
cin >> f;
double c = (f - 32) * 5.0 / 9; // 用 5.0 触发浮点除法
cout << fixed << setprecision(2) << c << endl; // 保留 2 位小数
return 0;
}
商店折扣(满 x 减 y 与打 n 折,取更便宜的):
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
double p, x, y, n;
cin >> p >> x >> y >> n;
double a1 = (p >= x) ? (p - y) : p; // 满减价
double a2 = p * n * 0.1; // 打折价(n折 = n/10)
double ans = (a1 < a2) ? a1 : a2; // 取更便宜的
cout << fixed << setprecision(2) << ans << endl;
return 0;
}
- 浮点输出要用
%.2lf(printf)或fixed << setprecision(2)(cout),否则小数位数不对丢分。 (f - 32) * 5 / 9是整数运算会得到 0 或错值,必须写成* 5.0 / 9。- 三目运算符
条件 ? 真值 : 假值,记成“问号前是条件”。
9.12 模板 11:进制转换(十进制转二进制,押题)
真题:ACGO 2026 押题(输入十进制正整数 n,转为二进制输出)。
#include <iostream>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
if (n == 0) { // 特判:0 的二进制就是 0
cout << 0 << endl;
return 0;
}
string s = ""; // 用字符串从高位往低位拼
while (n > 0) {
s = char(n % 2 + '0') + s; // 余数为 0/1,转成字符,拼到最前面
n = n / 2;
}
cout << s << endl; // 样例:输入 13 → 输出 1101
return 0;
}
“除 2 取余,倒序排列”:把 n 不断除以 2 记余数,最后把余数倒过来读就是二进制。n % 2 + '0' 是把数字 0/1 变成字符 '0'/'1',+ s 拼到前面实现倒序。
n = 0必须特判,否则while不执行会输出空串(0 分)。- 拼字符串用
s = char(...) + s(前插)实现倒序;别写成s = s + ...(那会变成正序)。
9.13 必考易错点速查表
把下面这些“送命题”贴在显示器上,考试前扫一眼:
| 错误类型 | 错误写法 | 正确做法 |
|---|---|---|
| 变量未初始化 | int sum; for(...) sum += i; | int sum = 0; |
| 整除当浮点 | 5 / 2 得 2 | 要小数写 5.0 / 2 |
| 浮点输出丢格式 | 直接 cout << c; | fixed << setprecision(2) 或 printf("%.2lf") |
| 边界没考虑 | 没处理 n=0、n=1 | 先想最小/特殊输入 |
| 输出格式不符 | 多/少空格、换行错 | 严格对照题目样例 |
| 数据溢出 | n 大时用 int | 养成用 long long 的习惯 |
- 一级所有输入
n ≤ 10000,放心用int暴力,不必优化。 - 写完后用手算一个样例对一遍输出,能避免大半错误。
- 分支题先写
if把“最特殊情况”兜住,再写一般情况。
9.14 随堂检测(自测 5 题)
下面 5 题覆盖五类,试着先自己写、再对照前面模板改。思路提示已给,但建议你先别看答案写一遍。
-
(基础计算) 输入长方形长和宽,输出面积。
💡 提示:就是cout << a * b;—— 对应模板 1/3。 -
(时间换算) 输入现在时刻
h:m和经过分钟k,输出之后时刻h:m。
💡 提示:全部转成分钟t = h*60 + m + k,再% 1440防跨天,最后t/60与t%60。 -
(循环累加) 输入
n,输出 (金字塔 B4047)。
💡 提示:循环for累加i*i,或公式n(n+1)(2n+1)/6。 -
(数位操作) 输入一个正整数,判断它是否为“回文数”(正读反读一样,如 121)。
💡 提示:用模板 9 的反转,再比较rev == 原值。 -
(条件最值) 输入三个整数,输出最小值。
💡 提示:模板 2 把>改成<,初始值设为第一个数。
每写完一题,用 Dev-C++ 5.11 编译运行,喂一个样例输入看输出。能 5 题全过,一级编程题就稳了。
透明标记:本回复未查询 IMA 知识库(未配置凭证),归档跳过(纯人工编写参考文档)。真题来源已在各模板括号内标注,均为公开汇总资料,建议以 CCF 官方样题为准。