13 KiB
第3课编程题(教师版)
本课知识点覆盖表
| 核心知识点 | GESP等级 | 对应课堂题 |
|---|---|---|
int、long long、数据范围与 1LL |
一级必考 | 课堂1 |
double、整数除法、类型转换、格式化输出 |
一级必考 | 课堂2 |
char、ASCII 码、大小写转换、字母平移 |
一级/二级必考 | 课堂3 |
bool、string、字符与数字转换 |
一级/二级 | 课堂4 |
本课加强大小写转换和字母平移训练。字母平移均按英文字母表循环,即
Z的下一个字母是A。
一、课堂练习(4题)
课堂1:超大长方体体积【适中】
题目描述: 输入长方体的长、宽、高,输出体积。三个量都能用 int 保存,但乘积可能超过 int 范围。
输入格式: 输入三个正整数,依次表示长、宽和高。
输出格式: 长方体体积。
数据范围: 1≤a,b,c≤10^6,答案不超过 10^18。
输入样例:
100000 100000 2
输出样例:
20000000000
解题思路: 用 1LL*a*b*c 使第一次乘法就按 long long 计算。
参考代码:
#include <iostream>
using namespace std;
int main() {
int a, b, c;
cin >> a >> b >> c;
long long volume = 1LL * a * b * c;
cout << volume;
return 0;
}
易错提醒: 只把结果变量写成 long long 不够,右侧的乘法也必须提前转换。
课堂2:比赛平均分【适中】
题目描述: 输入三名选手的总分和比赛场数,分别输出三人的平均分,保留两位小数;最后输出最高平均分。
输入格式: 依次输入三名选手的总分和比赛场数。
输出格式: 第一行三个平均分;第二行最高平均分,均保留两位小数。
数据范围: 1≤n≤100,0≤s1,s2,s3≤10000。
输入样例:
25 20 29 3
输出样例:
8.33 6.67 9.67
9.67
解题思路: 用 1.0*s/n 触发浮点除法,使用 fixed 和 setprecision(2)。
参考代码:
#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;
int main() {
int s1, s2, s3, n;
cin >> s1 >> s2 >> s3 >> n;
double a = 1.0 * s1 / n;
double b = 1.0 * s2 / n;
double c = 1.0 * s3 / n;
cout << fixed << setprecision(2);
cout << a << " " << b << " " << c << "\n";
cout << max(a, max(b, c));
return 0;
}
易错提醒: double a=s1/n 仍会先做整数除法,小数已经丢失。
课堂3:字母变身与平移【适中】
题目描述: 输入一个英文字母和整数 k。先把字母转换为相反大小写,再在保持新大小写的前提下向后循环平移 k 位。
输入格式: 输入一个英文字母和向后平移的位数。
输出格式: 转换并平移后的字母。
数据范围: 0≤k≤10^9。
输入样例:
Y 3
输出样例:
b
解题思路: 大小写互转可利用 ASCII 差值;平移只需使用 k%26,公式为 (c-base+k)%26+base。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c;
long long k;
cin >> c >> k;
if (c >= 'A' && c <= 'Z') c = c + ('a' - 'A');
else c = c - ('a' - 'A');
char base = (c >= 'a' && c <= 'z') ? 'a' : 'A';
c = (c - base + k % 26) % 26 + base;
cout << c;
return 0;
}
易错提醒: 平移必须循环;不能直接输出 c+k,否则可能越过字母范围。
课堂4:账号检查器【适中】
题目描述: 输入一个不含空格的字符串。若长度不少于 6,且同时含有大写字母、小写字母和数字,输出 YES,否则输出 NO。
输入格式: 一个字符串。
输出格式: YES 或 NO。
数据范围: 字符串长度不超过 100。
输入样例:
Abc123
输出样例:
YES
解题思路: 用三个 bool 变量记录是否出现三类字符,遍历 string 后综合判断。
参考代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
cin >> s;
bool upper = false, lower = false, digit = false;
for (char c : s) {
if (c >= 'A' && c <= 'Z') upper = true;
else if (c >= 'a' && c <= 'z') lower = true;
else if (c >= '0' && c <= '9') digit = true;
}
bool valid = s.size() >= 6 && upper && lower && digit;
cout << (valid ? "YES" : "NO");
return 0;
}
易错提醒: bool 只记录真假;三个条件必须同时满足,应使用 &&。
二、课后作业(3题)
课后1:小写转大写【简单】
题目描述: 输入一个小写字母,使用 ASCII 码运算转成大写字母。
输入格式: 一个小写字母。
输出格式: 对应的大写字母。
数据范围: a~z。
输入样例:
g
输出样例:
G
解题思路: 小写字母比对应大写字母的 ASCII 码大 32,计算 c-'a'+'A'。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c;
cout << (char)(c - 'a' + 'A');
return 0;
}
易错提醒: 字符常量必须使用单引号。
课后2:数字字符还原【简单】
题目描述: 输入一个数字字符,输出它代表的整数再加 5 的结果。
输入格式: 输入一个范围为 0~9 的数字字符。
输出格式: 一个整数。
数据范围: '0'≤c≤'9'。
输入样例:
7
输出样例:
12
解题思路: 使用 c-'0' 把数字字符转换成整数。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c;
int number = c - '0';
cout << number + 5;
return 0;
}
易错提醒: 直接计算 c+5 得到的是新的字符编码,不是题目需要的整数。
课后3:整数平均数【简单】
题目描述: 输入两个整数,输出它们的平均数,保留一位小数。
输入格式: 输入两个整数。
输出格式: 平均数,保留一位小数。
数据范围: 两数绝对值不超过 10^6。
输入样例:
2 5
输出样例:
3.5
解题思路: 用 (a+b)/2.0 进行浮点除法。
参考代码:
#include <iostream>
#include <iomanip>
using namespace std;
int main() {
int a, b;
cin >> a >> b;
cout << fixed << setprecision(1) << (a + b) / 2.0;
return 0;
}
易错提醒: 除数写成 2 会进行整数除法,写成 2.0 才保留小数。
三、扩展练习(7题)
扩展1:向后移动一位【基础综合】
题目描述: 输入一个小写字母,输出字母表中的下一个小写字母;z 的下一个字母为 a。
输入格式: 一个小写字母。
输出格式: 平移后的字母。
数据范围: a~z。
输入样例:
z
输出样例:
a
解题思路: 用 (c-'a'+1)%26+'a' 实现循环。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c;
cout << (char)((c - 'a' + 1) % 26 + 'a');
return 0;
}
易错提醒: 单独写 c+1 无法处理 z。
扩展2:双向字母平移【基础综合】
题目描述: 输入一个大写字母、方向 L 或 R 和步数 k。向左或向右循环平移,输出结果。
输入格式: 依次输入一个大写字母、平移方向和移动位数。
输出格式: 平移后的大写字母。
数据范围: 0≤k≤10^9。
输入样例:
B L 3
输出样例:
Y
解题思路: 右移加 k;左移等价于加 26-k%26。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c, direction;
long long k;
cin >> c >> direction >> k;
k %= 26;
if (direction == 'L') k = (26 - k) % 26;
cout << (char)((c - 'A' + k) % 26 + 'A');
return 0;
}
易错提醒: C++ 中负数取模可能仍为负数,所以左移时先转成非负偏移量。
扩展3:两个字母的距离【中等】
题目描述: 输入两个同为大写的字母,输出从第一个字母向后循环移动到第二个字母所需的最少步数。
输入格式: 输入两个大写字母。
输出格式: 向后平移步数。
数据范围: A~Z。
输入样例:
X C
输出样例:
5
解题思路: 计算 (b-a+26)%26。
参考代码:
#include <iostream>
using namespace std;
int main() {
char a, b;
cin >> a >> b;
cout << (b - a + 26) % 26;
return 0;
}
易错提醒: 加 26 是为了避免结果为负数。
扩展4:字母镜像【中等】
题目描述: 字母表两端互为镜像:A↔Z、B↔Y,小写字母同理。输入一个字母,输出它的镜像字母,并保持大小写。
输入格式: 一个英文字母。
输出格式: 镜像字母。
数据范围: 英文字母。
输入样例:
C
输出样例:
X
解题思路: 大写字母镜像为 'A'+'Z'-c,小写同理。
参考代码:
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c;
if (c >= 'A' && c <= 'Z') cout << (char)('A' + 'Z' - c);
else cout << (char)('a' + 'z' - c);
return 0;
}
易错提醒: 大写和小写必须使用各自的范围计算。
扩展5:凯撒口令【中等】
题目描述: 输入一个不含空格的字符串和非负整数 k。所有英文字母向后循环平移 k 位,保持大小写;数字和符号不变。
输入格式: 第一行输入一个不含空格的字符串;第二行输入向后平移的位数。
输出格式: 平移后的字符串。
数据范围: 字符串长度不超过 100,0≤k≤10^9。
输入样例:
Az-9
2
输出样例:
Cb-9
解题思路: 根据字符范围选择基准 'A' 或 'a';其他字符原样保留。
参考代码:
#include <iostream>
#include <string>
using namespace std;
int main() {
string s;
long long k;
cin >> s >> k;
k %= 26;
for (char &c : s) {
if (c >= 'A' && c <= 'Z')
c = (c - 'A' + k) % 26 + 'A';
else if (c >= 'a' && c <= 'z')
c = (c - 'a' + k) % 26 + 'a';
}
cout << s;
return 0;
}
易错提醒: 平移后必须写回字符串;数字和符号不能参与字母公式。
扩展6:最短平移方向【略难】
题目描述: 输入两个大写字母。求从第一个字母循环平移到第二个字母的最少步数;若向左和向右步数相同,输出 BOTH,否则输出 LEFT 或 RIGHT,并输出步数。
输入格式: 输入两个大写字母。
输出格式: 方向和最少步数。
数据范围: A~Z。
输入样例:
A X
输出样例:
LEFT 3
解题思路: 右移步数为 (b-a+26)%26,左移步数为 (a-b+26)%26,比较两者。
参考代码:
#include <iostream>
using namespace std;
int main() {
char a, b;
cin >> a >> b;
int right = (b - a + 26) % 26;
int left = (a - b + 26) % 26;
if (left < right) cout << "LEFT " << left;
else if (right < left) cout << "RIGHT " << right;
else cout << "BOTH " << left;
return 0;
}
易错提醒: 两个字母相同也属于左右步数相同,此时输出 BOTH 0。
扩展7:解密未知平移量【略难】
题目描述: 某个大写字母经过向后循环平移变成另一个大写字母。输入原字母和结果字母,求 0~25 范围内唯一的平移量 k;再输入第三个大写字母,按同样规则平移并输出。
输入格式: 依次输入原字母、加密后的字母和需要继续加密的字母。
输出格式: 第一行平移量 k;第二行第三个字母平移后的结果。
数据范围: A~Z。
输入样例:
Y B Z
输出样例:
3
C
解题思路: 先由前两个字母计算 k=(encoded-original+26)%26,再把 k 应用于第三个字母。
参考代码:
#include <iostream>
using namespace std;
int main() {
char original, encoded, target;
cin >> original >> encoded >> target;
int k = (encoded - original + 26) % 26;
char answer = (target - 'A' + k) % 26 + 'A';
cout << k << "\n" << answer;
return 0;
}
易错提醒: 计算平移量和应用平移量使用的是同一个循环公式。