582 lines
13 KiB
Markdown
582 lines
13 KiB
Markdown
# 第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 码运算转成大写字母。
|
||
|
||
**输入格式:** 一个小写字母。
|
||
|
||
**输出格式:** 对应的大写字母。
|
||
|
||
**数据范围:** `a~z`。
|
||
|
||
**输入样例:**
|
||
```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 的结果。
|
||
|
||
**输入格式:** 输入一个范围为 0~9 的数字字符。
|
||
|
||
**输出格式:** 一个整数。
|
||
|
||
**数据范围:** `'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`。
|
||
|
||
**输入格式:** 一个小写字母。
|
||
|
||
**输出格式:** 平移后的字母。
|
||
|
||
**数据范围:** `a~z`。
|
||
|
||
**输入样例:**
|
||
```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:两个字母的距离【中等】
|
||
|
||
**题目描述:** 输入两个同为大写的字母,输出从第一个字母向后循环移动到第二个字母所需的最少步数。
|
||
|
||
**输入格式:** 输入两个大写字母。
|
||
|
||
**输出格式:** 向后平移步数。
|
||
|
||
**数据范围:** `A~Z`。
|
||
|
||
**输入样例:**
|
||
```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`,并输出步数。
|
||
|
||
**输入格式:** 输入两个大写字母。
|
||
|
||
**输出格式:** 方向和最少步数。
|
||
|
||
**数据范围:** `A~Z`。
|
||
|
||
**输入样例:**
|
||
```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:解密未知平移量【略难】
|
||
|
||
**题目描述:** 某个大写字母经过向后循环平移变成另一个大写字母。输入原字母和结果字母,求 `0~25` 范围内唯一的平移量 `k`;再输入第三个大写字母,按同样规则平移并输出。
|
||
|
||
**输入格式:** 依次输入原字母、加密后的字母和需要继续加密的字母。
|
||
|
||
**输出格式:** 第一行平移量 `k`;第二行第三个字母平移后的结果。
|
||
|
||
**数据范围:** `A~Z`。
|
||
|
||
**输入样例:**
|
||
```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;
|
||
}
|
||
```
|
||
|
||
**易错提醒:** 计算平移量和应用平移量使用的是同一个循环公式。
|