Files
project1/第01课-数据类型与分支结构/数据类型-编程题-教师版.md

582 lines
13 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 第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 <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`
**输入样例:**
```text
25 20 29 3
```
**输出样例:**
```text
8.33 6.67 9.67
9.67
```
**解题思路:**`1.0*s/n` 触发浮点除法,使用 `fixed``setprecision(2)`
**参考代码:**
```cpp
#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`
**输入样例:**
```text
Y 3
```
**输出样例:**
```text
b
```
**解题思路:** 大小写互转可利用 ASCII 差值;平移只需使用 `k%26`,公式为 `(c-base+k)%26+base`
**参考代码:**
```cpp
#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。
**输入样例:**
```text
Abc123
```
**输出样例:**
```text
YES
```
**解题思路:** 用三个 `bool` 变量记录是否出现三类字符,遍历 `string` 后综合判断。
**参考代码:**
```cpp
#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 码运算转成大写字母。
**输入格式:** 一个小写字母。
**输出格式:** 对应的大写字母。
**数据范围:** `az`
**输入样例:**
```text
g
```
**输出样例:**
```text
G
```
**解题思路:** 小写字母比对应大写字母的 ASCII 码大 32计算 `c-'a'+'A'`
**参考代码:**
```cpp
#include <iostream>
using namespace std;
int main() {
char c;
cin >> c;
cout << (char)(c - 'a' + 'A');
return 0;
}
```
**易错提醒:** 字符常量必须使用单引号。
### 课后2数字字符还原【简单】
**题目描述:** 输入一个数字字符,输出它代表的整数再加 5 的结果。
**输入格式:** 输入一个范围为 09 的数字字符。
**输出格式:** 一个整数。
**数据范围:** `'0'≤c≤'9'`
**输入样例:**
```text
7
```
**输出样例:**
```text
12
```
**解题思路:** 使用 `c-'0'` 把数字字符转换成整数。
**参考代码:**
```cpp
#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`
**输入样例:**
```text
2 5
```
**输出样例:**
```text
3.5
```
**解题思路:**`(a+b)/2.0` 进行浮点除法。
**参考代码:**
```cpp
#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`
**输入格式:** 一个小写字母。
**输出格式:** 平移后的字母。
**数据范围:** `az`
**输入样例:**
```text
z
```
**输出样例:**
```text
a
```
**解题思路:**`(c-'a'+1)%26+'a'` 实现循环。
**参考代码:**
```cpp
#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`
**输入样例:**
```text
B L 3
```
**输出样例:**
```text
Y
```
**解题思路:** 右移加 `k`;左移等价于加 `26-k%26`
**参考代码:**
```cpp
#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两个字母的距离【中等】
**题目描述:** 输入两个同为大写的字母,输出从第一个字母向后循环移动到第二个字母所需的最少步数。
**输入格式:** 输入两个大写字母。
**输出格式:** 向后平移步数。
**数据范围:** `AZ`
**输入样例:**
```text
X C
```
**输出样例:**
```text
5
```
**解题思路:** 计算 `(b-a+26)%26`
**参考代码:**
```cpp
#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`,小写字母同理。输入一个字母,输出它的镜像字母,并保持大小写。
**输入格式:** 一个英文字母。
**输出格式:** 镜像字母。
**数据范围:** 英文字母。
**输入样例:**
```text
C
```
**输出样例:**
```text
X
```
**解题思路:** 大写字母镜像为 `'A'+'Z'-c`,小写同理。
**参考代码:**
```cpp
#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`
**输入样例:**
```text
Az-9
2
```
**输出样例:**
```text
Cb-9
```
**解题思路:** 根据字符范围选择基准 `'A'``'a'`;其他字符原样保留。
**参考代码:**
```cpp
#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`,并输出步数。
**输入格式:** 输入两个大写字母。
**输出格式:** 方向和最少步数。
**数据范围:** `AZ`
**输入样例:**
```text
A X
```
**输出样例:**
```text
LEFT 3
```
**解题思路:** 右移步数为 `(b-a+26)%26`,左移步数为 `(a-b+26)%26`,比较两者。
**参考代码:**
```cpp
#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解密未知平移量【略难】
**题目描述:** 某个大写字母经过向后循环平移变成另一个大写字母。输入原字母和结果字母,求 `025` 范围内唯一的平移量 `k`;再输入第三个大写字母,按同样规则平移并输出。
**输入格式:** 依次输入原字母、加密后的字母和需要继续加密的字母。
**输出格式:** 第一行平移量 `k`;第二行第三个字母平移后的结果。
**数据范围:** `AZ`
**输入样例:**
```text
Y B Z
```
**输出样例:**
```text
3
C
```
**解题思路:** 先由前两个字母计算 `k=(encoded-original+26)%26`,再把 `k` 应用于第三个字母。
**参考代码:**
```cpp
#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;
}
```
**易错提醒:** 计算平移量和应用平移量使用的是同一个循环公式。