# 第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`。 **输入样例:** ```text 100000 100000 2 ``` **输出样例:** ```text 20000000000 ``` **解题思路:** 用 `1LL*a*b*c` 使第一次乘法就按 `long long` 计算。 **参考代码:** ```cpp #include 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`。 **输入样例:** ```text 25 20 29 3 ``` **输出样例:** ```text 8.33 6.67 9.67 9.67 ``` **解题思路:** 用 `1.0*s/n` 触发浮点除法,使用 `fixed` 和 `setprecision(2)`。 **参考代码:** ```cpp #include #include #include 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`。 **输入样例:** ```text Y 3 ``` **输出样例:** ```text b ``` **解题思路:** 大小写互转可利用 ASCII 差值;平移只需使用 `k%26`,公式为 `(c-base+k)%26+base`。 **参考代码:** ```cpp #include 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。 **输入样例:** ```text Abc123 ``` **输出样例:** ```text YES ``` **解题思路:** 用三个 `bool` 变量记录是否出现三类字符,遍历 `string` 后综合判断。 **参考代码:** ```cpp #include #include 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`。 **输入样例:** ```text g ``` **输出样例:** ```text G ``` **解题思路:** 小写字母比对应大写字母的 ASCII 码大 32,计算 `c-'a'+'A'`。 **参考代码:** ```cpp #include using namespace std; int main() { char c; cin >> c; cout << (char)(c - 'a' + 'A'); return 0; } ``` **易错提醒:** 字符常量必须使用单引号。 ### 课后2:数字字符还原【简单】 **题目描述:** 输入一个数字字符,输出它代表的整数再加 5 的结果。 **输入格式:** 输入一个范围为 0~9 的数字字符。 **输出格式:** 一个整数。 **数据范围:** `'0'≤c≤'9'`。 **输入样例:** ```text 7 ``` **输出样例:** ```text 12 ``` **解题思路:** 使用 `c-'0'` 把数字字符转换成整数。 **参考代码:** ```cpp #include using namespace std; int main() { char c; cin >> c; int number = c - '0'; cout << number + 5; return 0; } ``` **易错提醒:** 直接计算 `c+5` 得到的是新的字符编码,不是题目需要的整数。 ### 课后3:整数平均数【简单】 **题目描述:** 输入两个整数,输出它们的平均数,保留一位小数。 **输入格式:** 输入两个整数。 **输出格式:** 平均数,保留一位小数。 **数据范围:** 两数绝对值不超过 `10^6`。 **输入样例:** ```text 2 5 ``` **输出样例:** ```text 3.5 ``` **解题思路:** 用 `(a+b)/2.0` 进行浮点除法。 **参考代码:** ```cpp #include #include 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`。 **输入样例:** ```text z ``` **输出样例:** ```text a ``` **解题思路:** 用 `(c-'a'+1)%26+'a'` 实现循环。 **参考代码:** ```cpp #include 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`。 **输入样例:** ```text B L 3 ``` **输出样例:** ```text Y ``` **解题思路:** 右移加 `k`;左移等价于加 `26-k%26`。 **参考代码:** ```cpp #include 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`。 **输入样例:** ```text X C ``` **输出样例:** ```text 5 ``` **解题思路:** 计算 `(b-a+26)%26`。 **参考代码:** ```cpp #include using namespace std; int main() { char a, b; cin >> a >> b; cout << (b - a + 26) % 26; return 0; } ``` **易错提醒:** 加 26 是为了避免结果为负数。 ### 扩展4:字母镜像【中等】 **题目描述:** 字母表两端互为镜像:`A↔Z`、`B↔Y`,小写字母同理。输入一个字母,输出它的镜像字母,并保持大小写。 **输入格式:** 一个英文字母。 **输出格式:** 镜像字母。 **数据范围:** 英文字母。 **输入样例:** ```text C ``` **输出样例:** ```text X ``` **解题思路:** 大写字母镜像为 `'A'+'Z'-c`,小写同理。 **参考代码:** ```cpp #include 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`。 **输入样例:** ```text Az-9 2 ``` **输出样例:** ```text Cb-9 ``` **解题思路:** 根据字符范围选择基准 `'A'` 或 `'a'`;其他字符原样保留。 **参考代码:** ```cpp #include #include 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`。 **输入样例:** ```text A X ``` **输出样例:** ```text LEFT 3 ``` **解题思路:** 右移步数为 `(b-a+26)%26`,左移步数为 `(a-b+26)%26`,比较两者。 **参考代码:** ```cpp #include 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`。 **输入样例:** ```text Y B Z ``` **输出样例:** ```text 3 C ``` **解题思路:** 先由前两个字母计算 `k=(encoded-original+26)%26`,再把 `k` 应用于第三个字母。 **参考代码:** ```cpp #include 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; } ``` **易错提醒:** 计算平移量和应用平移量使用的是同一个循环公式。