init: 12 lessons + outline
This commit is contained in:
160
第02课-循环结构/教案-学生版.md
Normal file
160
第02课-循环结构/教案-学生版.md
Normal file
@@ -0,0 +1,160 @@
|
||||
# 第2课:循环结构 + 数位拆解
|
||||
|
||||
## 教学目标
|
||||
- 掌握 for、while 和 do-while 循环的使用场景
|
||||
- 掌握数位拆解技巧(取个位、去个位)
|
||||
- 能用循环判断回文数
|
||||
- 了解水仙花数的判断方法
|
||||
|
||||
## 核心考点:循环边界与数位拆解
|
||||
|
||||
### 考什么
|
||||
判断循环次数和结束条件,并用循环完成求各位和、________数字、判断回文数等任务。
|
||||
|
||||
### 必须理解
|
||||
次数明确时常用________;结束条件更自然时常用________。数位拆解每轮依次完成:________、使用这一位、________。如果后面还要使用原数,必须先________。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
int num = ________;
|
||||
int rev = 0;
|
||||
while (num > 0) {
|
||||
int d = num ________ 10;
|
||||
rev = rev * ________ + d;
|
||||
num ________ 10;
|
||||
}
|
||||
```
|
||||
|
||||
### `do-while` 循环
|
||||
|
||||
`do-while` 的特点:循环体至少执行 ______ 次。
|
||||
|
||||
```cpp
|
||||
do {
|
||||
// 循环体
|
||||
} while (条件); // 结尾不要漏掉 ______
|
||||
```
|
||||
|
||||
### 常见错误
|
||||
- 忘记更新循环变量会发生什么?________________
|
||||
- `i < n` 与 `i <= n` 的执行次数有什么区别?____________
|
||||
- 为什么反转前要备份原数?________________
|
||||
|
||||
### 判断是否掌握
|
||||
- [ ] 我能判断循环的起点、终点和次数。
|
||||
- [ ] 我能写出取个位与去个位。
|
||||
- [ ] 我能独立完成数字反转。
|
||||
|
||||
---
|
||||
|
||||
## 课堂编程题
|
||||
|
||||
### 课堂1:奇偶分组统计【适中】
|
||||
|
||||
**题目描述:** 输入正整数 `n`,分别求 `1~n` 中奇数之和、偶数之和,并计算 `1~n` 的乘积。若乘积超过 `10^18`,输出 `TOO LARGE`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 第一行奇数和与偶数和;第二行乘积或 `TOO LARGE`。
|
||||
|
||||
**数据范围:** `1≤n≤30`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
9 6
|
||||
120
|
||||
```
|
||||
|
||||
**解题思路:** 一个 `for` 循环同时完成奇偶累加;累乘前判断 `product>10^18/i`,避免溢出。
|
||||
|
||||
**易错提醒:** 范围是 `1~n`,循环条件必须为 `i<=n`;累加器和累乘器的初值分别为 0 和 1。
|
||||
|
||||
---
|
||||
|
||||
### 课堂2:数字分析报告【适中】
|
||||
|
||||
**题目描述:** 输入一个非负整数,输出它的位数、各位数字之和、最大数字和反转数。
|
||||
|
||||
**输入格式:** 输入一个非负整数。
|
||||
|
||||
**输出格式:** 依次输出位数、各位和、最大数字、反转数。
|
||||
|
||||
**数据范围:** `0≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
50230
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
5 10 5 3205
|
||||
```
|
||||
|
||||
**解题思路:** 备份原数,用 `while` 重复"取个位、使用个位、去个位";单独处理 `n=0`。
|
||||
|
||||
**易错提醒:** 反转后的前导零不会保留;0 本身有一位,不能被普通循环漏掉。
|
||||
|
||||
---
|
||||
|
||||
### 课堂3:寻找第一个合格数【适中】
|
||||
|
||||
**题目描述:** 从 `1~n` 中寻找第一个同时满足"能被 7 整除、不能被 5 整除、各位和大于 10"的数。跳过所有含数字 4 的数;找到后立即输出,否则输出 `NONE`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 第一个合格数或 `NONE`。
|
||||
|
||||
**数据范围:** `1≤n≤100000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
100
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
77
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举数字;拆位检查含 4 和各位和。含 4 时 `continue`,找到答案时 `break`。
|
||||
|
||||
**易错提醒:** `continue` 跳过本轮,`break` 结束整个当前循环,两者含义不同。
|
||||
|
||||
---
|
||||
|
||||
### 课堂4:区间素数统计【适中·双层循环】
|
||||
|
||||
**题目描述:** 输入 `L` 和 `R`,输出闭区间内的所有素数及素数个数。
|
||||
|
||||
**输入格式:** 输入区间的左端点和右端点。
|
||||
|
||||
**输出格式:** 第一行按升序输出素数;第二行输出个数。没有素数时第一行输出 `NONE`。
|
||||
|
||||
**数据范围:** `1≤L≤R≤10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 20
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
11 13 17 19
|
||||
4
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举候选数,内层从 2 检查到平方根;找到因数立即 `break`。
|
||||
|
||||
**易错提醒:** 1 不是素数;内层的 `break` 只结束因数检查,不会结束外层枚举。
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
|
||||
> 请完成本课对应的课后作业,见编程题文件。
|
||||
198
第02课-循环结构/教案-教师版.md
Normal file
198
第02课-循环结构/教案-教师版.md
Normal file
@@ -0,0 +1,198 @@
|
||||
# 第2课:循环结构 + 数位拆解
|
||||
|
||||
## 教学目标
|
||||
- 掌握 for、while 和 do-while 循环的使用场景
|
||||
- 掌握数位拆解技巧(取个位、去个位)
|
||||
- 能用循环判断回文数
|
||||
- 了解水仙花数的判断方法
|
||||
|
||||
## 核心考点:循环边界与数位拆解
|
||||
|
||||
### 考什么
|
||||
常见题型要求重复执行固定次数、在条件成立时持续循环,或逐位处理一个整数,例如求各位和、反转数字、判断回文数。考点既包括循环写法,也包括循环何时开始、何时结束。
|
||||
|
||||
### 必须理解
|
||||
`for` 适合次数明确的重复,`while` 适合结束条件更自然的过程。数位拆解每轮做三件事:`n % 10` 取个位,使用这个个位完成统计或拼接,`n /= 10` 去掉个位。因为 n 会不断变小,若后面还要与原数比较,必须提前备份。循环边界要保证每个需要处理的值恰好进入一次,不能漏掉终点或多执行一轮。
|
||||
|
||||
### 核心写法
|
||||
```cpp
|
||||
int original = n;
|
||||
int reversed = 0;
|
||||
while (n > 0) {
|
||||
int digit = n % 10;
|
||||
reversed = reversed * 10 + digit;
|
||||
n /= 10;
|
||||
}
|
||||
bool isPalindrome = (reversed == original);
|
||||
```
|
||||
取位、使用、去位的顺序不能乱;`n /= 10` 还保证循环最终结束。
|
||||
|
||||
### `do-while` 循环
|
||||
|
||||
`do-while` 会先执行循环体,再判断条件,因此循环体至少执行一次。适合“先操作一次,再决定是否继续”的场景。
|
||||
|
||||
```cpp
|
||||
int number;
|
||||
do {
|
||||
cin >> number;
|
||||
} while (number != 0);
|
||||
```
|
||||
|
||||
注意结尾的分号不能漏掉。三种循环选择原则:次数明确优先 `for`;先判断再重复常用 `while`;至少执行一次使用 `do-while`。
|
||||
|
||||
### 常见错误
|
||||
- 忘记备份原数,拆解结束后 n 已变成 0。
|
||||
- 忘记更新循环变量,造成死循环。
|
||||
- 把 `i < n` 和 `i <= n` 混用,导致少算或多算一次。
|
||||
- 反转数字时漏写 `reversed * 10`,无法给新个位腾出位置。
|
||||
|
||||
### 判断是否掌握
|
||||
能判断一个任务该用 `for` 还是 `while`,能准确写出循环范围,并能独立完成取个位、去个位、求各位和或反转数字。
|
||||
|
||||
---
|
||||
|
||||
## 题目一:判断回文数
|
||||
|
||||
### 核心代码(一句话)
|
||||
> 回文数的核心:**把数字反转,看反转后和原数是否相等。** 反转靠三行代码——取个位、拼新数、去个位。
|
||||
|
||||
### 自然语言思路
|
||||
回文数就是"正着读反着读都一样"的数,比如 12321、4554、7。
|
||||
|
||||
**怎么判断?分三步走:**
|
||||
|
||||
**第一步:备份原数。** 因为待会儿要拆解它,拆完就没了,所以先用 `temp = n` 把原数存好。
|
||||
|
||||
**第二步:反转数字。** 这是核心!口诀:**"取个位、拼新数、去个位"**,循环直到原数变成 0。
|
||||
|
||||
以 123 为例,手推一遍:
|
||||
|
||||
| 轮次 | 原数 temp | 个位 d = temp%10 | 反转数 rev = rev×10+d | temp = temp/10 |
|
||||
|------|-----------|-------------------|------------------------|-----------------|
|
||||
| 第1轮 | 123 | 3 | 0×10+3 = **3** | 12 |
|
||||
| 第2轮 | 12 | 2 | 3×10+2 = **32** | 1 |
|
||||
| 第3轮 | 1 | 1 | 32×10+1 = **321** | 0 |
|
||||
| 结束 | 0 | — | **321** | — |
|
||||
|
||||
反转 123 得到 321。这个过程就像把数字"倒着拼回去"。
|
||||
|
||||
**第三步:比较。** 原数 n(备份的)和反转数 rev 相等 → 回文数!
|
||||
|
||||
### 伪代码
|
||||
```
|
||||
输入 n
|
||||
temp = n // 备份原数
|
||||
rev = 0 // 反转数初始为0
|
||||
当 temp > 0:
|
||||
d = temp % 10 // 取个位
|
||||
rev = rev * 10 + d // 拼到反转数的末尾
|
||||
temp = temp / 10 // 去掉个位
|
||||
如果 rev == n:
|
||||
输出 "是回文数"
|
||||
否则:
|
||||
输出 "不是回文数"
|
||||
```
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
|
||||
int rev = 0; // 存放反转后的数
|
||||
int temp = n; // 备份原数,因为要拆解
|
||||
|
||||
while (temp > 0) {
|
||||
int d = temp % 10; // ① 取个位
|
||||
rev = rev * 10 + d; // ② 拼到新数末尾
|
||||
temp /= 10; // ③ 去掉个位
|
||||
}
|
||||
|
||||
if (rev == n) {
|
||||
cout << "是回文数" << endl;
|
||||
} else {
|
||||
cout << "不是回文数" << endl;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
### 注意点
|
||||
1. **一定要备份原数**:`temp = n` 这一步不能省!否则 n 被拆解成 0 了,最后没法比较。
|
||||
2. **`while` vs `for`**:数位拆解用 `while` 更自然,因为事先不知道数字有几位。`for` 适用于知道循环次数的情况。
|
||||
3. **`temp % 10` 取个位**:任何整数模 10 就得到个位。如 12345 % 10 = 5。
|
||||
4. **`temp / 10` 去个位**:整数除法自动舍去余数。如 12345 / 10 = 1234。
|
||||
5. **边界:0 和负数**:0 是回文数(0反转还是0)。负数一般不算回文数(-121 反转是 121-),GESP 一级不会考负数回文。
|
||||
6. **循环终止条件**:`temp > 0`,不是 `temp >= 0`(会导致死循环,因为 0/10 还是 0)。
|
||||
|
||||
---
|
||||
|
||||
## 题目二:(待橙子补充)
|
||||
|
||||
> 建议覆盖:水仙花数、for循环基本用法等
|
||||
|
||||
---
|
||||
|
||||
### 核心代码(一句话)
|
||||
>
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
|
||||
### 伪代码
|
||||
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
|
||||
```
|
||||
|
||||
### 注意点
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 题目三:(待橙子补充)
|
||||
|
||||
> 建议覆盖:break/continue、循环综合练习等
|
||||
|
||||
---
|
||||
|
||||
### 核心代码(一句话)
|
||||
>
|
||||
|
||||
### 自然语言思路
|
||||
|
||||
|
||||
### 伪代码
|
||||
|
||||
|
||||
### 真实代码
|
||||
```cpp
|
||||
|
||||
```
|
||||
|
||||
### 注意点
|
||||
|
||||
|
||||
---
|
||||
|
||||
## 本课打油诗
|
||||
|
||||
> **(数位拆解)**
|
||||
> 循环取位倒着排,个位拼到新数来。
|
||||
> 除十去尾继续转,正反相等回文哉。
|
||||
|
||||
> **(回文数判断)**
|
||||
> 反转数字比原数,相等就是回文数。
|
||||
> 备份原数不能忘,拆完再比才无误。
|
||||
|
||||
---
|
||||
|
||||
## 课后作业
|
||||
(待补充)
|
||||
1.
|
||||
2.
|
||||
690
第02课-循环结构/编程题-教师版.md
Normal file
690
第02课-循环结构/编程题-教师版.md
Normal file
@@ -0,0 +1,690 @@
|
||||
# 第5课编程题(教师版)
|
||||
|
||||
## 本课知识点覆盖表
|
||||
|
||||
| 核心知识点 | GESP等级 | 对应课堂题 |
|
||||
|---|---|---|
|
||||
| `for`、累加、累乘与循环边界 | 一级必考 | 课堂1 |
|
||||
| `while`、取个位、去个位、数字反转 | 一级/二级 | 课堂2 |
|
||||
| `break`、`continue` 与循环控制 | 一级必考 | 课堂3 |
|
||||
| 双层循环、外层枚举对象、内层检查条件 | 一级巩固/二级 | 课堂4 |
|
||||
|
||||
> 本课包含 6 道双层循环题,作为第 6 课嵌套循环的过渡。
|
||||
|
||||
## 一、课堂练习(4题)
|
||||
|
||||
### 课堂1:奇偶分组统计【适中】
|
||||
|
||||
**题目描述:** 输入正整数 `n`,分别求 `1~n` 中奇数之和、偶数之和,并计算 `1~n` 的乘积。若乘积超过 `10^18`,输出 `TOO LARGE`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 第一行奇数和与偶数和;第二行乘积或 `TOO LARGE`。
|
||||
|
||||
**数据范围:** `1≤n≤30`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
9 6
|
||||
120
|
||||
```
|
||||
|
||||
**解题思路:** 一个 `for` 循环同时完成奇偶累加;累乘前判断 `product>10^18/i`,避免溢出。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
long long oddSum = 0, evenSum = 0, product = 1;
|
||||
bool tooLarge = false;
|
||||
cin >> n;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
if (i % 2 == 0) evenSum += i;
|
||||
else oddSum += i;
|
||||
if (!tooLarge) {
|
||||
if (product > 1000000000000000000LL / i) tooLarge = true;
|
||||
else product *= i;
|
||||
}
|
||||
}
|
||||
cout << oddSum << " " << evenSum << "\n";
|
||||
if (tooLarge) cout << "TOO LARGE";
|
||||
else cout << product;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 范围是 `1~n`,循环条件必须为 `i<=n`;累加器和累乘器的初值分别为 0 和 1。
|
||||
|
||||
### 课堂2:数字分析报告【适中】
|
||||
|
||||
**题目描述:** 输入一个非负整数,输出它的位数、各位数字之和、最大数字和反转数。
|
||||
|
||||
**输入格式:** 输入一个非负整数。
|
||||
|
||||
**输出格式:** 依次输出位数、各位和、最大数字、反转数。
|
||||
|
||||
**数据范围:** `0≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
50230
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
5 10 5 3205
|
||||
```
|
||||
|
||||
**解题思路:** 备份原数,用 `while` 重复“取个位、使用个位、去个位”;单独处理 `n=0`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <algorithm>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
if (n == 0) {
|
||||
cout << "1 0 0 0";
|
||||
return 0;
|
||||
}
|
||||
int temp = n, count = 0, sum = 0, biggest = 0, reversed = 0;
|
||||
while (temp > 0) {
|
||||
int digit = temp % 10;
|
||||
count++;
|
||||
sum += digit;
|
||||
biggest = max(biggest, digit);
|
||||
reversed = reversed * 10 + digit;
|
||||
temp /= 10;
|
||||
}
|
||||
cout << count << " " << sum << " " << biggest << " " << reversed;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 反转后的前导零不会保留;0 本身有一位,不能被普通循环漏掉。
|
||||
|
||||
### 课堂3:寻找第一个合格数【适中】
|
||||
|
||||
**题目描述:** 从 `1~n` 中寻找第一个同时满足“能被 7 整除、不能被 5 整除、各位和大于 10”的数。跳过所有含数字 4 的数;找到后立即输出,否则输出 `NONE`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 第一个合格数或 `NONE`。
|
||||
|
||||
**数据范围:** `1≤n≤100000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
100
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
77
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举数字;拆位检查含 4 和各位和。含 4 时 `continue`,找到答案时 `break`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, answer = -1;
|
||||
cin >> n;
|
||||
for (int x = 1; x <= n; x++) {
|
||||
int temp = x, sum = 0;
|
||||
bool hasFour = false;
|
||||
while (temp > 0) {
|
||||
int digit = temp % 10;
|
||||
if (digit == 4) hasFour = true;
|
||||
sum += digit;
|
||||
temp /= 10;
|
||||
}
|
||||
if (hasFour) continue;
|
||||
if (x % 7 == 0 && x % 5 != 0 && sum > 10) {
|
||||
answer = x;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (answer == -1) cout << "NONE";
|
||||
else cout << answer;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** `continue` 跳过本轮,`break` 结束整个当前循环,两者含义不同。
|
||||
|
||||
### 课堂4:区间素数统计【适中·双层循环】
|
||||
|
||||
**题目描述:** 输入 `L` 和 `R`,输出闭区间内的所有素数及素数个数。
|
||||
|
||||
**输入格式:** 输入区间的左端点和右端点。
|
||||
|
||||
**输出格式:** 第一行按升序输出素数;第二行输出个数。没有素数时第一行输出 `NONE`。
|
||||
|
||||
**数据范围:** `1≤L≤R≤10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 20
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
11 13 17 19
|
||||
4
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举候选数,内层从 2 检查到平方根;找到因数立即 `break`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int L, R, count = 0;
|
||||
cin >> L >> R;
|
||||
for (int x = L; x <= R; x++) {
|
||||
if (x < 2) continue;
|
||||
bool prime = true;
|
||||
for (int d = 2; d * d <= x; d++) {
|
||||
if (x % d == 0) {
|
||||
prime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prime) {
|
||||
if (count) cout << " ";
|
||||
cout << x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) cout << "NONE";
|
||||
cout << "\n" << count;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 1 不是素数;内层的 `break` 只结束因数检查,不会结束外层枚举。
|
||||
|
||||
## 二、课后作业(3题)
|
||||
|
||||
### 课后1:从 1 加到 n【简单】
|
||||
|
||||
**题目描述:** 输入 `n`,用循环求 `1+2+…+n`。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 累加和。
|
||||
|
||||
**数据范围:** `1≤n≤10^6`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
15
|
||||
```
|
||||
|
||||
**解题思路:** 累加器从 0 开始,循环范围为 `1~n`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
long long sum = 0;
|
||||
cin >> n;
|
||||
for (int i = 1; i <= n; i++) sum += i;
|
||||
cout << sum;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 和可能超过 `int`,使用 `long long`。
|
||||
|
||||
### 课后2:各位数字之和【简单】
|
||||
|
||||
**题目描述:** 输入一个正整数,输出各位数字之和。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 各位数字之和。
|
||||
|
||||
**数据范围:** `1≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
5082
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
15
|
||||
```
|
||||
|
||||
**解题思路:** 每轮用 `n%10` 取个位并累加,再用 `n/=10` 去个位。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, sum = 0;
|
||||
cin >> n;
|
||||
while (n > 0) {
|
||||
sum += n % 10;
|
||||
n /= 10;
|
||||
}
|
||||
cout << sum;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 循环内必须更新 `n`,否则会形成死循环。
|
||||
|
||||
### 课后3:跳过 3 的倍数【简单】
|
||||
|
||||
**题目描述:** 输出 `1~n` 中所有不是 3 的倍数的数。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 符合条件的数,以空格分隔。
|
||||
|
||||
**数据范围:** `1≤n≤100`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
7
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1 2 4 5 7
|
||||
```
|
||||
|
||||
**解题思路:** 遇到 3 的倍数时使用 `continue`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
bool first = true;
|
||||
cin >> n;
|
||||
for (int i = 1; i <= n; i++) {
|
||||
if (i % 3 == 0) continue;
|
||||
if (!first) cout << " ";
|
||||
cout << i;
|
||||
first = false;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 输出空格时用 `first` 控制,可避免行末多余空格。
|
||||
|
||||
## 三、扩展练习(7题)
|
||||
|
||||
### 扩展1:回文数判断【基础综合】
|
||||
|
||||
**题目描述:** 输入一个非负整数,判断是否为回文数。
|
||||
|
||||
**输入格式:** 输入一个非负整数。
|
||||
|
||||
**输出格式:** 是回文数输出 `YES`,否则输出 `NO`。
|
||||
|
||||
**数据范围:** `0≤n≤10^9`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
12321
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
YES
|
||||
```
|
||||
|
||||
**解题思路:** 备份原数,构造反转数并比较。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, temp, reversed = 0;
|
||||
cin >> n;
|
||||
temp = n;
|
||||
while (temp > 0) {
|
||||
reversed = reversed * 10 + temp % 10;
|
||||
temp /= 10;
|
||||
}
|
||||
cout << (reversed == n ? "YES" : "NO");
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 0 的反转仍是 0,因此程序也能正确判断。
|
||||
|
||||
### 扩展2:三位水仙花数【中等·双层思维】
|
||||
|
||||
**题目描述:** 输出 `100~n` 中所有水仙花数。三位数各位数字立方和等于原数时称为水仙花数。
|
||||
|
||||
**输入格式:** 输入一个整数,表示枚举范围的上界。
|
||||
|
||||
**输出格式:** 所有水仙花数,以空格分隔;没有则输出 `NONE`。
|
||||
|
||||
**数据范围:** `100≤n≤999`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
400
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
153 370 371
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举三位数,内层 `while` 拆出三位并累加立方。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, count = 0;
|
||||
cin >> n;
|
||||
for (int x = 100; x <= n; x++) {
|
||||
int temp = x, sum = 0;
|
||||
while (temp > 0) {
|
||||
int d = temp % 10;
|
||||
sum += d * d * d;
|
||||
temp /= 10;
|
||||
}
|
||||
if (sum == x) {
|
||||
if (count) cout << " ";
|
||||
cout << x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) cout << "NONE";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 判断时要与原数 `x` 比较,不能与已变成 0 的 `temp` 比较。
|
||||
|
||||
### 扩展3:因数清单【中等·双层循环】
|
||||
|
||||
**题目描述:** 对 `1~n` 中的每个数,输出该数及它的所有正因数,每个数占一行。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 第 `x` 行先输出 `x:`,再输出 `x` 的所有正因数。
|
||||
|
||||
**数据范围:** `1≤n≤30`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
3
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
1: 1
|
||||
2: 1 2
|
||||
3: 1 3
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举数字 `x`,内层枚举可能的因数 `d`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n;
|
||||
cin >> n;
|
||||
for (int x = 1; x <= n; x++) {
|
||||
cout << x << ":";
|
||||
for (int d = 1; d <= x; d++) {
|
||||
if (x % d == 0) cout << " " << d;
|
||||
}
|
||||
cout << "\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 内层上界随当前数字 `x` 变化,不是固定使用 `n`。
|
||||
|
||||
### 扩展4:完数统计【中等·双层循环】
|
||||
|
||||
**题目描述:** 一个正整数的所有真因数(不含自身)之和等于它本身,则称为完数。输出 `2~n` 中所有完数。
|
||||
|
||||
**输入格式:** 输入一个正整数。
|
||||
|
||||
**输出格式:** 所有完数;没有则输出 `NONE`。
|
||||
|
||||
**数据范围:** `2≤n≤10000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
30
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
6 28
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举候选数,内层枚举 `1~x/2` 并累加因数。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, count = 0;
|
||||
cin >> n;
|
||||
for (int x = 2; x <= n; x++) {
|
||||
int sum = 0;
|
||||
for (int d = 1; d <= x / 2; d++) {
|
||||
if (x % d == 0) sum += d;
|
||||
}
|
||||
if (sum == x) {
|
||||
if (count) cout << " ";
|
||||
cout << x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) cout << "NONE";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 真因数不包含自身;每次检查新数字时 `sum` 都要清零。
|
||||
|
||||
### 扩展5:乘积等于目标的数对【中等·双层循环】
|
||||
|
||||
**题目描述:** 输入 `n` 和目标 `m`,输出所有满足 `1≤a<b≤n` 且 `a*b=m` 的数对。
|
||||
|
||||
**输入格式:** 输入枚举上界和目标乘积。
|
||||
|
||||
**输出格式:** 每行一对 `a b`;没有则输出 `NONE`。
|
||||
|
||||
**数据范围:** `1≤n≤1000`,`1≤m≤10^6`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 24
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
3 8
|
||||
4 6
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举 `a`,内层只从 `a+1` 枚举 `b`,避免重复和 `a=b`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, m, count = 0;
|
||||
cin >> n >> m;
|
||||
for (int a = 1; a <= n; a++) {
|
||||
for (int b = a + 1; b <= n; b++) {
|
||||
if (a * b == m) {
|
||||
cout << a << " " << b << "\n";
|
||||
count++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (count == 0) cout << "NONE";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** `b` 从 `a+1` 开始,才能保证每个无序数对只输出一次。
|
||||
|
||||
### 扩展6:回文素数【略难·双层循环】
|
||||
|
||||
**题目描述:** 输出 `L~R` 中既是回文数又是素数的数。
|
||||
|
||||
**输入格式:** 输入区间的左端点和右端点。
|
||||
|
||||
**输出格式:** 所有回文素数;没有则输出 `NONE`。
|
||||
|
||||
**数据范围:** `1≤L≤R≤100000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 150
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
11 101 131
|
||||
```
|
||||
|
||||
**解题思路:** 外层枚举;先反转判断回文,通过后再用内层循环判断素数。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int L, R, count = 0;
|
||||
cin >> L >> R;
|
||||
for (int x = L; x <= R; x++) {
|
||||
int temp = x, reversed = 0;
|
||||
while (temp > 0) {
|
||||
reversed = reversed * 10 + temp % 10;
|
||||
temp /= 10;
|
||||
}
|
||||
if (reversed != x || x < 2) continue;
|
||||
|
||||
bool prime = true;
|
||||
for (int d = 2; d * d <= x; d++) {
|
||||
if (x % d == 0) {
|
||||
prime = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (prime) {
|
||||
if (count) cout << " ";
|
||||
cout << x;
|
||||
count++;
|
||||
}
|
||||
}
|
||||
if (count == 0) cout << "NONE";
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 先判断回文可减少素数检查次数;1 仍然不是素数。
|
||||
|
||||
### 扩展7:最接近目标的因数积【略难·双层循环】
|
||||
|
||||
**题目描述:** 输入 `n` 和目标 `target`。在所有满足 `1≤a≤b≤n` 的数对中,寻找乘积与目标差的绝对值最小的一对;并列时先选较小的 `a`,再选较小的 `b`。
|
||||
|
||||
**输入格式:** 输入数对中每个数的上界和目标值。
|
||||
|
||||
**输出格式:** 输出 `a b a*b`。
|
||||
|
||||
**数据范围:** `1≤n≤500`,`1≤target≤250000`。
|
||||
|
||||
**输入样例:**
|
||||
```text
|
||||
10 53
|
||||
```
|
||||
|
||||
**输出样例:**
|
||||
```text
|
||||
6 9 54
|
||||
```
|
||||
|
||||
**解题思路:** 双层枚举所有合法数对,用二次打擂台比较乘积距离、`a`、`b`。
|
||||
|
||||
**参考代码:**
|
||||
```cpp
|
||||
#include <iostream>
|
||||
#include <cmath>
|
||||
using namespace std;
|
||||
|
||||
int main() {
|
||||
int n, target;
|
||||
cin >> n >> target;
|
||||
int bestA = 1, bestB = 1;
|
||||
for (int a = 1; a <= n; a++) {
|
||||
for (int b = a; b <= n; b++) {
|
||||
int now = a * b;
|
||||
int best = bestA * bestB;
|
||||
if (abs(now - target) < abs(best - target) ||
|
||||
(abs(now - target) == abs(best - target) && a < bestA) ||
|
||||
(abs(now - target) == abs(best - target) &&
|
||||
a == bestA && b < bestB)) {
|
||||
bestA = a;
|
||||
bestB = b;
|
||||
}
|
||||
}
|
||||
}
|
||||
cout << bestA << " " << bestB << " " << bestA * bestB;
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
**易错提醒:** 枚举范围允许 `a=b`;并列规则必须按顺序完整处理。
|
||||
Reference in New Issue
Block a user