Files
project1/第11课-GESP二级真题训练一/教案-教师版.md

293 lines
10 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.
# 第11课综合练习
## 教学目标
- 混合题型训练,覆盖一二级核心知识点
- 查漏补缺,找到薄弱环节
- 提高解题速度和准确率
## 核心考点:混合题的拆解与算法组合
### 考什么
综合题不会直接告诉你使用哪一课的知识,而是把输入输出、分支、循环、数组、字符串等组合起来。考试重点是从题意中识别若干小任务,为每个小任务选择已经学过的代码模式,再按正确顺序连接。
### 必须理解
先把题目拆成“输入什么→处理什么→输出什么”三段。处理部分继续拆成动作,例如“遍历数组→筛选满足条件的元素→打擂台求最值→输出下标”。每个动作只解决一个问题,再把前一步结果交给下一步。读到“每个”通常想到遍历,读到“最大/最小”想到打擂台,读到“出现次数”想到计数,读到“如果/否则”想到分支。组合算法时要明确数据在各步骤中的含义,不能边读题边盲写代码。
### 核心写法
```text
1. 圈出输入、输出和数据范围
2. 把处理过程拆成若干小任务
3. 为每个小任务选择代码模板
4. 确定各步骤先后与中间变量
5. 写代码后用样例和边界值检查
```
例如“找数组中出现次数最多的数”可拆成:数组输入 + 频次统计 + 打擂台 + 输出答案。
### 常见错误
- 一看到长题目就直接写代码,没有先拆任务。
- 只完成主算法,漏掉输入格式、并列规则或输出顺序。
- 不区分中间变量的含义,把下标、数值和次数混用。
- 只测试题目样例,不测试空边界、最小值、最大值或并列情况。
### 判断是否掌握
拿到一道混合题,能在动手前写出清晰的三到五步伪代码,并能指出每一步使用了哪种基础结构或算法模板。
---
## 题目一:成绩等级判断(分支 + 输入输出)
### 核心代码(一句话)
> 多分支判断的核心:**`if - else if - else` 链条**,从大到小或从小到大依次判断,每种情况一个分支。
### 自然语言思路
输入一个 0-100 的成绩输出对应的等级90-100 → A80-89 → B70-79 → C60-69 → D60以下 → E。
第一步,接收输入 `score`
第二步,从高分往低分判断:`if (score >= 90)` → A`else if (score >= 80)` → B依次类推。
第三步,最后一个 `else` 兜底,对应 E 等级。
第四步,注意判断顺序:如果从小到大判断(先 `score < 60`),要看清楚边界别重叠。
> GESP 考试中这类题会以"程序阅读"或"编程题"形式出现,要注意 if-else 的匹配逻辑。
### 伪代码
```
1. 输入 score
2. if score >= 90 输出 "A"
3. else if score >= 80 输出 "B"
4. else if score >= 70 输出 "C"
5. else if score >= 60 输出 "D"
6. else 输出 "E"
```
### 真实代码
```cpp
#include <iostream>
using namespace std;
int main() {
int score;
cin >> score;
if (score >= 90) {
cout << "A" << endl;
} else if (score >= 80) {
cout << "B" << endl;
} else if (score >= 70) {
cout << "C" << endl;
} else if (score >= 60) {
cout << "D" << endl;
} else {
cout << "E" << endl;
}
return 0;
}
```
### 注意点
1. **判断顺序很重要**:从大到小写最清晰,因为 `else if` 意味着"前面条件都不满足"。如果从小到大写,要注意边界。
2. **边界值**90 是 A89 是 B。如果写成 `score > 90` 就会把 90 分的人划到 B检查时要留意。
3. **输入范围**:题目保证输入在 0-100但实际考试中如果输入 101 按上面代码会输出 "A"(因为 ≥90。严谨的做法是加范围检查。
---
## 题目二:数组求最大值及下标(数组 + 循环 + 打擂台)
### 核心代码(一句话)
> 带下标记录的打擂台:**用一个变量记最大值,另一个变量记下标**,每次换擂主时两个一起更新。
### 自然语言思路
输入 n 个数,输出最大值和它第一次出现的下标。
第一步,读入数组。
第二步,设 `maxVal = arr[0]``maxIndex = 0`,两个变量一起初始化为第一个元素的值和下标。
第三步,从 `i = 1` 开始遍历,如果 `arr[i] > maxVal`(严格大于),则同时更新 `maxVal = arr[i]``maxIndex = i`
第四步,遍历结束,输出最大值和下标。
> 注意是"严格大于" `>`,不是 `>=`。如果写成 `>=`,遇到重复最大值时会记录最后一次出现的位置。
### 伪代码
```
1. 输入 n
2. 读入数组 arr[n]
3. maxVal = arr[0], maxIndex = 0
4. for i = 1 到 n-1
5. if arr[i] > maxVal // 严格大于
6. maxVal = arr[i]
7. maxIndex = i
8. 输出 maxVal 和 maxIndex
```
### 真实代码
```cpp
#include <iostream>
using namespace std;
int main() {
int n;
cin >> n;
int arr[n];
for (int i = 0; i < n; i++) {
cin >> arr[i];
}
int maxVal = arr[0];
int maxIndex = 0;
for (int i = 1; i < n; i++) {
if (arr[i] > maxVal) {
maxVal = arr[i];
maxIndex = i;
}
}
cout << "最大值:" << maxVal << ",下标:" << maxIndex << endl;
return 0;
}
```
### 注意点
1. **`>` vs `>=`**:用 `>` 保留第一次出现的下标,用 `>=` 保留最后一次出现的下标。看题目要求。
2. **maxIndex 初始值**:必须和 maxVal 的初始值对应。如果 maxVal 从 arr[0] 开始maxIndex 就是 0。
3. **循环从 1 开始**:因为 arr[0] 已经是初始擂主了。
---
## 题目三字符串分类统计string + 字符判断 + 多计数器)
### 核心代码(一句话)
> 字符串分类统计的核心:**遍历 + 多分支判断 + 多个计数器**,每个 `if` 分支对应一个计数器。
### 自然语言思路
输入一行字符串,统计其中大写字母、小写字母、数字、其他字符(含空格)各有多少个。
第一步,用 `getline(cin, s)` 读入整行(因为可能含空格)。
第二步,设四个计数器 `upper, lower, digit, other` 都初始为 0。
第三步,遍历每个字符 `s[i]`,用 `isupper``islower``isdigit` 判断类型,对应计数器 +1。
第四步,都不满足的归入 `other`
第五步,输出四个统计结果。
第六步,注意空格也算"其他",如果不想算空格可以先单独判断 `s[i] == ' '`
### 伪代码
```
1. getline 读取字符串 s
2. upper = 0, lower = 0, digit = 0, other = 0
3. for i = 0 到 s.length()-1
4. if isupper(s[i]) upper++
5. else if islower(s[i]) lower++
6. else if isdigit(s[i]) digit++
7. else other++
8. 输出四个计数结果
```
### 真实代码
```cpp
#include <iostream>
#include <string>
#include <cctype>
using namespace std;
int main() {
string s;
getline(cin, s);
int upper = 0, lower = 0, digit = 0, other = 0;
for (int i = 0; i < s.length(); i++) {
if (isupper(s[i])) {
upper++;
} else if (islower(s[i])) {
lower++;
} else if (isdigit(s[i])) {
digit++;
} else {
other++;
}
}
cout << "大写:" << upper
<< ",小写:" << lower
<< ",数字:" << digit
<< ",其他:" << other << endl;
return 0;
}
```
### 注意点
1. **`getline` 不是 `cin`**`cin >> s` 遇空格就停,"Hello World" 只会读到 "Hello"。
2. **`isupper` 等函数需要 `<cctype>`**:别忘了加这个头文件。
3. **else 分支的归属**:空格、标点符号都会进 `other`。如果题目要求单独统计空格,需要在 `else` 前加 `else if (s[i] == ' ')`
4. **空的字符串**:如果什么都没输入,四个计数器都是 0输出全零不会出错。
---
## 限时练习(课堂完成)
### 练习组一(限时 30 分钟)
1. 输入两个数,输出较大的数(基础输入输出 + if
2. 输入 n输出 n 的阶乘 `1 × 2 × 3 × ... × n`(循环 + 累乘)
3. 输入一个字符串判断是否为回文string + 循环)
### 练习组二(限时 30 分钟)
1. 输入 n 个数,求平均值(数组 + 求和 + 浮点数)
2. 找出 100 以内的所有素数(循环 + 判断素数)
3. 输入一个正整数,输出它的逆序数(如 12345 → 54321数位拆解
### 练习组三(限时 30 分钟)
1. 输入年份,判断是否为闰年(能被 4 整除且不能被 100 整除,或能被 400 整除)
2. 输入 n打印左下直角三角形嵌套循环
3. 输入一个字符串统计其中数字的个数string + isdigit
---
## 解题技巧
### 1. 仔细审题
- 看清输入输出格式(空格、换行、大小写)
- 注意数据范围(决定用 `int` 还是 `long long`
- 理解题目要求(从小到大输出还是从大到小)
### 2. 先想后写
- 在草稿纸上写出核心步骤
- 用伪代码搭好骨架
- 再动手写真实代码
### 3. 测试验证
- 先用样例数据测试
- 再试边界情况0、1、最大值、最小值
- 检查输出格式是否完全一致
### 4. 时间管理
- 先做简单的题,拿稳基础分
- 不会的题先跳过,不要死磕
- 留 10 分钟检查
---
## 常见错误检查清单
在交卷前逐条检查:
- [ ] 头文件是否包含(`<iostream>``<string>``<cmath>``<cctype>` 等)
- [ ] `using namespace std;` 是否写了
- [ ] 变量是否初始化(特别是累加器、计数器)
- [ ] 数组下标是否越界(从 0 到 n-1
- [ ] 循环边界是否正确(`<` vs `<=`
- [ ] 输出格式是否正确(空格、换行、中文/英文标点)
- [ ] 是否处理了边界情况0、1、负数等
- [ ] 整数除法是否需要转浮点数
- [ ] string 输入是否用了 `getline`(含空格时)
---
## 本课打油诗
> 综合练习查漏洞,各种题型过一遍。
> 先审题意后动手,伪代码里思路现。
> 边界条件要想全,样例测完再交卷。
> 时间分配有策略,不会先跳回头见。
---
## 课后作业
1. 补完课堂限时练习中未完成的题目
2. 整理自己的错题本,写出错误原因和正确解法
3. 在洛谷上完成 GESP 一级真题中的 3 道编程题