NOI C++ 课程体系 / 语法入门 / 第5讲
CSP-J 入门级 · 语法入门 · for循环专题

C++ for 循环 完全指南

让计算机替你重复做事 —— 从高斯算数到质数判断,从语法解剖到算法思维,一站式掌握 for 循环。

6 大教学模块 6 个精讲案例 3 种循环对比 5 大易错点 12 道分层练习
本讲 · 第 9/56 讲for 循环语句
模块 01

情景导航

先用故事和生活中的场景建立直觉,再给出严谨的编程定义,最后用表格和口诀把核心要点固化下来。

故事故事引入 —— 小高斯与"1加到100"

传说,18世纪末的德国,有一位名叫高斯的数学神童。他上小学的时候,老师为了让学生们安静一会儿,在黑板上写了一道题:

"请把 1 到 100 的所有整数加起来,算出结果。"

老师心想:这些小家伙肯定要一个一个加半天,我正好可以歇会儿。没想到,没过多久,小高斯就把写满答案的小石板举了起来——答案是 5050。

老师很惊讶,问他是怎麼算的。高斯说:

"我把1和100配对,2和99配对,3和98配对……每一对加起来都是101,一共有50对,所以50×101=5050。"

💡 两种解法,殊途同归

高斯用了数学巧思,但如果让计算机来算呢?它最擅长的就是"不知疲倦地重复"!

解法思路时间复杂度特点
方法一:循环累加从1加到100,一个一个加O(n)适合学习循环,通用性强
方法二:公式计算n×(n+1)/2O(1)更快,但只适用于等差数列

方法一用代码怎么写?

C++方法一:for 循环累加
int sum = 0;
for (int i = 1; i <= 100; i++) {
    sum = sum + i;   // 每轮把 i 加进 sum
}
// 结果:sum = 5050

方法二呢?

C++方法二:公式法
int n = 100;
int sum = n * (n + 1) / 2;
// 结果:sum = 5050

今天,我们就来学习"方法一"背后的核心语法 —— for 循环

①生活类比 —— 循环就是"按套路重复"

在写代码之前,先想一想生活里那些"反复做、直到满足某个条件才停下"的事情。

🏃

操场跑 10 圈

老师规定跑 10 圈,你每跑完一圈就数一次数,数到 10 就停。次数是提前知道的。

→ 对应 for 循环
🚌

等公交车

你站在站台等车,每隔几秒看一眼有没有车来,有车了就上车走人。不知道等几秒,但知道停的条件。

→ 对应 while 循环
🍚

吃饭

先盛一碗饭吃一口,然后判断"饱了吗"?没饱就继续吃,饱了就停。至少吃一口,先执行后判断。

→ 对应 do-while 循环
📅

翻日历

从1月翻到12月,每翻一页看看"到12月了吗?",到了就停。已知范围,逐步推进。

→ 对应 for 循环
②编程定义 —— for 循环是什么?

在编程中,for 循环是一种重复执行代码的控制结构。它让你只需要写一次代码,计算机就会按照你的要求重复执行指定的次数。

核心思想:"给一个起始值,规定一个结束条件,每轮做完后做一个变化",然后计算机自动帮你跑完整个过程。

📌 三种循环语句对比

循环类型判断时机适用场景最少执行次数
for先判断,后执行已知循环次数0 次
while先判断,后执行未知次数,依赖条件0 次
do-while先执行,后判断至少执行一次1 次
③核心要点 —— 循环三要素与口诀

不管用哪种循环,都离不开三个要素:初始化 → 条件判断 → 步进变化。缺一不可,否则就会出 bug。

🔑 记忆口诀

for 循环三要素,初值 · 条件 · 步进不能少;
初值只跑一次头,条件不满足就溜;
步进每轮末尾走,循环体里干正事;
三要素缺一不可,死循环了别喊救!

模块 02

知识探究

深入 for 循环的语法细节,通过 6 个由浅入深的案例,掌握 for 循环的各种用法。

1语法详解 —— for 循环的"解剖"

for 循环由三个表达式和一个循环体组成:

for ( int i = 1 ; i <= 100 ; i++ ) {
  // 循环体
}
① 初始化(只执行1次) ② 条件判断(每轮检查) ③ 步进变化(每轮末尾) ④ 循环体
执行流程

Step 1:执行初始化(如 int i = 1)—— 只在循环开始前执行一次
Step 2:判断条件(如 i <= 100)—— 为 true 进入循环体,为 false 退出
Step 3:执行循环体中的代码
Step 4:执行步进(如 i++)—— 然后回到 Step 2

🎬 动画演示:for(int i=1; i<=5; i++) 执行过程

1
int i = 1 —— 初始化,i 被赋值为 1
2
判断 i <= 5(1 <= 5)?✅ 成立,进入循环体
3
执行 cout << i,输出 1
4
i++,i 变为 2 → 回到判断
5
判断 i <= 5(2 <= 5)?✅ → 输出 2 → i++ → i=3
6
判断 ✅ → 输出 3 → i=4 → 输出 4 → i=5 → 输出 5 → i=6
7
判断 6 <= 5?❌ 不成立 → 退出循环
✓
循环结束!共输出:1 2 3 4 5

📏 关键规则:

  • 三个表达式都可以省略,但分号不能省:for(;;) 是死循环
  • 循环变量推荐当场定义(作用域仅限 for 内部,更安全)
  • 步进可以是任意表达式:i+=2(每次加2)、i*=2(每次乘2)、i--(倒着走)
  • 循环体如果只有一条语句,花括号 {} 可以省略(但不推荐,容易出错)
2易混淆概念对比辨析
for 循环 vs while 循环
  • for:适合已知循环次数的场景
  • while:适合未知循环次数,依赖条件判断
  • 本质上 for 可以改写为 while,反之亦然
  • for 内定义的变量,循环结束后自动销毁
break vs continue
  • break:直接跳出整个循环,后续不再执行
  • continue:跳过本轮剩余代码,进入下一轮
  • break 是"彻底走人",continue 是"这轮算了,下轮再来"
  • 两者只能用于循环和 switch 中
3案例解析 —— 由浅入深 6 个案例

案例 1:输出 1 到 100 最基础

题目:用 for 循环输出 1 到 100 之间的所有整数,每行一个。

C++输出1到100
#include <iostream>
using namespace std;
int main(){
    for(int i = 1; i <= 100; i++){
        cout << i << endl;
    }
    return 0;
}
代码行说明
for(int i = 1; i <= 100; i++)i 从 1 开始,每次加 1,直到 100
cout << i << endl;输出当前 i 的值并换行
运行结果(前5行 + 末行)
1
2
3
4
5
...
100

案例 2:累加求和 累加器模式

题目:计算 1+2+3+...+100 的总和。

C++累加器模式
#include <iostream>
using namespace std;
int main(){
    int sum = 0;  // ⚠️ 累加器必须初始化为 0!
    for(int i = 1; i <= 100; i++){
        sum += i;   // 等价于 sum = sum + i
    }
    cout << "1+2+...+100 = " << sum << endl;
    return 0;
}
关键代码说明
int sum = 0;声明累加器并初始化为 0(不初始化会得到垃圾值)
sum += i;每轮把 i 加到 sum 中:0→1→3→6→10→...→5050
运行结果
1+2+...+100 = 5050

案例 3:判断质数 O(√n) 优化

题目:输入一个整数 n(n ≥ 2),判断它是否是质数。

质数:只能被 1 和它本身整除的大于 1 的自然数。

❌ 方法一:暴力 O(n) 慢
bool isPrime = true;
for(int i = 2; i < n; i++){
    if(n % i == 0){
        isPrime = false;
        break;
    }
}

n=10⁹ 时要循环 10⁹ 次,太慢!

✅ 方法二:优化 O(√n) 快
bool isPrime = true;
for(int i = 2; i * i <= n; i++){
    if(n % i == 0){
        isPrime = false;
        break; // 找到因子立即退出
    }
}

n=10⁹ 时只需循环约 31622 次!

C++完整程序(优化版)
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    if(n < 2){
        cout << "N" << endl;
        return 0;
    }
    bool isPrime = true;
    for(int i = 2; i * i <= n; i++){  // 关键:只需试到 √n
        if(n % i == 0){
            isPrime = false;
            break;  // 找到因子,立即退出!
        }
    }
    if(isPrime) cout << "Y" << endl;
    else        cout << "N" << endl;
    return 0;
}

💡 为什么只需试到 √n?

如果 n 有一个大于 √n 的因子 d,那 n/d 一定是小于 √n 的因子。所以只要 √n 以内没找到因子,n 就一定是质数!

例:n=36,√36=6。因子对:(1,36)(2,18)(3,12)(4,9)(6,6),每对中小因子都 ≤ 6。

运行结果
输入: 7     → 输出: Y
输入: 12    → 输出: N
输入: 999999937 → 输出: Y(大质数也能秒出结果)

案例 4:用 continue 求奇数和 continue 用法

题目:计算 1 到 n 中所有奇数的和,用 continue 跳过偶数。

C++continue 跳过偶数
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    int sum = 0;
    for(int i = 1; i <= n; i++){
        if(i % 2 == 0){
            continue;  // 偶数?跳过!不执行后面的 sum += i
        }
        sum += i;  // 只有奇数才会执行到这里
    }
    cout << "奇数和 = " << sum << endl;
    return 0;
}
执行过程(n=6)i 的值i%2==0?动作sum
第1轮1否sum += 11
第2轮2是continue 跳过1
第3轮3否sum += 34
第4轮4是continue 跳过4
第5轮5否sum += 59
第6轮6是continue 跳过9
运行结果
输入: 6
输出: 奇数和 = 9  (1+3+5=9)

案例 5:阶乘计算 累乘器模式

题目:输入 n,计算 n! = 1 × 2 × 3 × ... × n。

C++阶乘(累乘器)
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    long long prod = 1;  // ⚠️ 累乘器初始化为 1(不是 0!)
    for(int i = 1; i <= n; i++){
        prod *= i;  // 等价于 prod = prod * i
    }
    cout << n << "! = " << prod << endl;
    return 0;
}

💡 累加器 vs 累乘器

累加器:int sum = 0; → sum += i;(初始化为 0)

累乘器:long long prod = 1; → prod *= i;(初始化为 1)

为什么用 long long?因为阶乘增长极快:20! = 2432902008176640000,已经超出 int 范围!

运行结果
输入: 5   → 输出: 5! = 120
输入: 10  → 输出: 10! = 3628800
输入: 20  → 输出: 20! = 2432902008176640000

案例 6:九九乘法表 嵌套循环

题目:用嵌套 for 循环输出九九乘法表。

C++嵌套循环 — 九九乘法表
#include <iostream>
using namespace std;
int main(){
    for(int i = 1; i <= 9; i++){       // 外层:控制行数
        for(int j = 1; j <= i; j++){   // 内层:控制每行列数
            cout << j << "×" << i << "=" << i*j << "\t";
        }
        cout << endl;  // 每行结束换行
    }
    return 0;
}
嵌套规则说明
外层 i 走一步内层 j 要走完全套(从1到i)
总执行次数1+2+3+...+9 = 45 次
变量命名外层用 i,内层用 j,不能重名
运行结果
1×1=1
1×2=2   2×2=4
1×3=3   2×3=6   3×3=9
1×4=4   2×4=8   3×4=12  4×4=16
1×5=5   2×5=10  3×5=15  4×5=20  5×5=25
1×6=6   2×6=12  3×6=18  4×6=24  5×6=30  6×6=36
1×7=7   2×7=14  3×7=21  4×7=28  5×7=35  6×7=42  7×7=49
1×8=8   2×8=16  3×8=24  4×8=32  5×8=40  6×8=48  7×8=56  8×8=64
1×9=9   2×9=18  3×9=27  4×9=36  5×9=45  6×9=54  7×9=63  8×9=72  9×9=81
模块 03

实践应用

通过完整的编程题目,练习 for 循环的实际应用。每道题包含题目描述、输入输出样例、多种解法分析。

题1计算区间中奇数和与偶数和

题目描述:计算 m 到 n(0 ≤ m ≤ n ≤ 1000)之间所有偶数的和及奇数的和并输出。

输入样例:100 200   输出样例:7650 7500

方法一:遍历判断法

C++遍历判断
#include <iostream>
using namespace std;
int main(){
    int m, n;
    cin >> m >> n;
    int evenSum = 0, oddSum = 0;
    for(int i = m; i <= n; i++){
        if(i % 2 == 0) evenSum += i;
        else            oddSum  += i;
    }
    cout << evenSum << " " << oddSum << endl;
    return 0;
}

方法二:步进优化法 效率×2

C++步进优化(每次+2)
#include <iostream>
using namespace std;
int main(){
    int m, n;
    cin >> m >> n;
    int evenSum = 0, oddSum = 0;
    // 偶数:找到第一个偶数,每次+2
    for(int i = (m%2==0 ? m : m+1); i <= n; i += 2)
        evenSum += i;
    // 奇数:找到第一个奇数,每次+2
    for(int i = (m%2!=0 ? m : m+1); i <= n; i += 2)
        oddSum += i;
    cout << evenSum << " " << oddSum << endl;
    return 0;
}

💡 思考:如果范围扩大到 10⁹?

两种方法都需要循环数亿次。你能用等差数列求和公式在 O(1) 时间内算出结果吗?

提示:偶数和 = (首项 + 末项) × 项数 / 2

题2输出区间中能被3整除的第一个数字

题目描述:输出 m 到 n 之间能被 3 整除的第一个数字。找不到则输出 0。

输入样例:250 750   输出样例:252

C++break 提前退出
#include <iostream>
using namespace std;
int main(){
    int m, n;
    cin >> m >> n;
    int ans = 0;
    for(int i = m; i <= n; i++){
        if(i % 3 == 0){
            ans = i;
            break;  // ✅ 找到第一个就跳出,不再继续循环
        }
    }
    cout << ans << endl;
    return 0;
}

说明:用 break 在找到目标后立即跳出循环,避免无意义的遍历。这是 for 循环中非常实用的优化技巧。

题3水仙花数

题目描述:水仙花数是一个三位数,其各位数字的立方和等于该数本身。例如:153 = 1³ + 5³ + 3³。

C++枚举所有三位数
#include <iostream>
using namespace std;
int main(){
    for(int n = 100; n <= 999; n++){
        int a = n / 100;         // 百位
        int b = (n / 10) % 10;   // 十位
        int c = n % 10;         // 个位
        if(a*a*a + b*b*b + c*c*c == n){
            cout << n << " ";
        }
    }
    cout << endl;
    return 0;
}
运行结果
153 370 371 407
模块 04

总结提升

回顾核心要点,掌握万能模板,通过一题多解深化理解。

1核心要点总结
for 循环万能模板

for( 初始化 ; 条件判断 ; 步进变化 ) { 循环体 }

三要素缺一不可:初值 → 条件 → 步进

模式代码模板初始值
累加器sum += i;int sum = 0;
累乘器prod *= i;long long prod = 1;
计数器cnt++;int cnt = 0;
找最大if(x > max) max = x;max = 第一个数
找最小if(x < min) min = x;min = 第一个数
提前退出if(找到) break;—
跳过本轮if(不要) continue;—
2拓展 —— 一题多解

计算 1 到 n 的和:循环 vs 公式

方法一:for 循环 O(n)
int n, sum = 0;
cin >> n;
for(int i = 1; i <= n; i++)
    sum += i;
cout << sum;

通用性强,任何累加都能用

方法二:公式法 O(1) 百万倍快
long long n;
cin >> n;
cout << n*(n+1)/2;

n=10⁹ 时公式秒出,循环要跑 10⁹ 次

3思考与启发

💡 学完 for 循环,你应该明白的道理

1. 同一个问题可以有多种解法,有的简单直观(暴力枚举),有的高效优雅(数学公式)。

2. for 循环适合穷举场景——当答案空间有限时,把每种可能都试一遍。

3. 当数据量很大时,要想办法缩小搜索范围(如 √n 优化)或利用数学规律。

4. 写代码前先想清楚三件事:从哪开始?什么时候停?每次怎么变?

模块 05

学习检测

5 个典型错误,看看你能不能全部识别?每个错误都附有正确写法和预防口诀。

错误 1

忘记步进 → 死循环

❌ 错误代码
for(int i = 1; i <= 10; ){
    cout << i << " ";
}
💡 报错原因
缺少步进表达式,i 始终为 1,条件永远成立,程序卡死!
✅ 正确写法
for(int i = 1; i <= 10; i++){
    cout << i << " ";
}
预防口诀:for 里面步进不能忘,i++ 放在末尾上。
错误 2

循环变量作用域混淆

❌ 错误代码
for(int i = 1; i <= 5; i++){
    cout << i;
}
cout << i; // 编译报错!i 已销毁
💡 报错原因
for 内定义的 i,循环结束后自动销毁,外部无法访问。
✅ 正确写法
int i; // 提到外面定义
for(i = 1; i <= 5; i++){
    cout << i;
}
cout << i; // ✅ 此时 i = 6
预防口诀:循环变量作用域,for 内定义出不了。
错误 3

break 和 continue 混淆

❌ 错误代码
for(int i=1; i<=10; i++){
  if(i%2==0) break;
  cout << i << " ";
}
// 只输出: 1
💡 报错原因
break 跳出整个循环,i=2 时就走了。应该用 continue 跳过偶数。
✅ 正确写法
for(int i=1; i<=10; i++){
  if(i%2==0) continue;
  cout << i << " ";
}
// 输出: 1 3 5 7 9
预防口诀:break 是走人,continue 是跳过这轮。
错误 4

累加器未初始化

❌ 错误代码
int sum; // 未初始化!
for(int i=1;i<=100;i++)
    sum += i;
// 结果:随机垃圾值
💡 报错原因
局部变量未初始化时值是随机的(垃圾值),累加结果不可预测。
✅ 正确写法
int sum = 0; // 必须初始化为0
for(int i=1;i<=100;i++)
    sum += i;
// 结果:5050 ✅
预防口诀:累加变量要初始化,sum=0 不能丢。
错误 5

嵌套循环变量名冲突

❌ 错误代码
for(int i=1;i<=3;i++){
  for(int i=1;i<=3;i++){
    cout << i;
  }
}
💡 报错原因
内外层都用了变量名 i,内层遮蔽外层,导致外层循环异常。
✅ 正确写法
for(int i=1;i<=3;i++){
  for(int j=1;j<=3;j++){
    cout << j;
  }
}
预防口诀:嵌套循环变量名,i、j、k 各用各的。
速查for 循环易错点速查表
错误类型症状原因解决方法
死循环程序卡住不输出缺少步进或条件永真检查步进,确保条件能变假
变量未初始化结果随机/错误累加器/计数器未设初值sum=0, cnt=0, prod=1
作用域错误编译报错循环外用 for 内变量在循环外声明变量
break/continue输出不完整该用 continue 时用了 break跳出全部→break,跳本轮→continue
变量名冲突嵌套结果异常内外层用了相同变量名外层 i,内层 j/k
off-by-one多算或少算一个<= 和 < 搞混手动验证首尾值
📌知识点笔记 —— for 循环速记卡

📝 语法模板

for(初始化; 条件; 步进) { 循环体 }

🎯 三要素

① 初始化:从哪开始(只执行1次)

② 条件:什么时候停(每轮检查)

③ 步进:每次怎么变(每轮末尾)

⚠️ 常见陷阱

• 忘记步进 → 死循环

• 累加器没初始化 → 垃圾值

• <=100 写成 <100 → 少算一个

• break/continue 搞混

🔧 常用模式

• 累加:sum=0 → sum+=i

• 累乘:prod=1 → prod*=i

• 计数:cnt=0 → cnt++

• 提前退出:break

课后练习

分层练习作业

A 基础 / B 提高 / C 挑战,难度递增,点击展开答案与解析。

总结练习3 道综合题
A 基础 洛谷 P1036 选数

题目:从 n 个数中选 k 个数的和为素数

题目描述:已知 n 个整数 x1, x2, ..., xn,以及一个整数 k(k < n)。从 n 个整数中任选 k 个整数相加,求和为素数的种数。

输入样例:4 2 1 2 3 4

输出样例:4

提示:用 for 循环嵌套 + 素数判断函数,枚举所有 C(n,k) 种组合。
点击查看参考答案与解析
C++参考代码
#include <iostream>
using namespace std;
bool isPrime(int n){
    if(n < 2) return false;
    for(int i = 2; i*i <= n; i++){
        if(n % i == 0) return false;
    }
    return true;
}
int main(){
    int n, k;
    cin >> n >> k;
    int a[25];
    for(int i = 0; i < n; i++) cin >> a[i];
    int cnt = 0;
    // 枚举所有C(n,k)组合(此处用递归回溯实现)
    // 简化版:k=2时用两层for
    for(int i = 0; i < n; i++){
        for(int j = i+1; j < n; j++){
            if(isPrime(a[i]+a[j])) cnt++;
        }
    }
    cout << cnt << endl;
    return 0;
}

解析:外层 for 选第一个数,内层 for 选第二个数(j > i 避免重复),判断和是否为素数。素数判断也用 for 循环试除到 sqrt(n)。

B 提高 洛谷 P1215 等差数列

题目:等差数列

题目描述:给定一个等差数列的首项 a1 和公差 d,求前 n 项的和。

输入样例:1 2 10(首项=1,公差=2,项数=10)

输出样例:100

提示:第 i 项 = a1 + (i-1)*d,用 for 循环累加。
点击查看参考答案与解析
C++参考代码
#include <iostream>
using namespace std;
int main(){
    int a1, d, n;
    cin >> a1 >> d >> n;
    int sum = 0;
    for(int i = 1; i <= n; i++){
        int ai = a1 + (i-1)*d;  // 第i项
        sum += ai;
    }
    cout << sum << endl;
    return 0;
}

解析:用 for 循环从第 1 项到第 n 项,逐项计算并累加。也可以用公式 sum = n*(2*a1 + (n-1)*d) / 2 直接计算。

C 挑战 洛谷 P1423 小玉在游泳

题目:小玉在游泳

题目描述:小玉在水里游泳,第一下能游 2 米,以后每下比之前多游 0.5 米。请问她需要游多少下才能游过 n 米?

输入样例:4.3

输出样例:2

提示:用 while 或 for 循环,每游一下累加距离,直到总距离超过 n。
点击查看参考答案与解析
C++参考代码
#include <iostream>
using namespace std;
int main(){
    double n;
    cin >> n;
    double dist = 0, step = 2.0;
    int cnt = 0;
    while(dist < n){
        dist += step;
        step += 0.5;
        cnt++;
    }
    cout << cnt << endl;
    return 0;
}

解析:用 while 循环模拟游泳过程,每游一下距离增加当前步长,步长每次增加 0.5,直到总距离超过目标。也可用 for 循环改写。

🟢 A 组 · 基础(4 题)

A1累加求和

求 1 到 n 的和

输入:100 → 输出:5050

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, sum = 0;
    cin >> n;
    for(int i = 1; i <= n; i++) sum += i;
    cout << sum << endl;
}

思路:准备一个累加变量从 0 开始,让循环变量从 1 走到 n 逐个加进去。

易错:累加变量没有初始化为 0,结果带上随机值;或循环写成 i < n 少加最后一项。

A2阶乘

求 n!(n 的阶乘)

输入:5 → 输出:120

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n;
    long long prod = 1;
    cin >> n;
    for(int i = 1; i <= n; i++) prod *= i;
    cout << prod << endl;
}

思路:连乘的初始值必须取 1,且阶乘增长很快,结果要用 long long 存。

易错:乘积初始值写成 0 导致结果恒为 0;用 int 存 20! 会溢出(20! 约 2.4×10¹⁸,远超 21 亿)。

A3计数

统计 1~n 中能被 3 整除的数的个数

输入:30 → 输出:10

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, cnt = 0;
    cin >> n;
    for(int i = 1; i <= n; i++)
        if(i % 3 == 0) cnt++;
    cout << cnt << endl;
}

思路:遍历 1~n,用 i % 3 == 0 判断能否被 3 整除,成立就把计数器加一。

易错:把判断写成 i / 3 == 0;或写成 i % 3 = 0(单等号是赋值,编译报错)。

A4最大最小值

输入 n 个整数,找出最大值和最小值

输入:5 3 7 2 9 5 → 输出:9 2

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, a, maxv, minv;
    cin >> n >> a;
    maxv = minv = a;
    for(int i = 2; i <= n; i++){
        cin >> a;
        if(a > maxv) maxv = a;
        if(a < minv) minv = a;
    }
    cout << maxv << " " << minv << endl;
}

思路:把读到的第一个数同时当作最大值和最小值的初值,之后每读一个数就更新一次。

易错:把初值写死成 0,数据全是负数时最大值会错;循环次数写成 i <= n 会多读一个数。

🟡 B 组 · 提高(4 题)

B1质因数分解

已知 n 是两个不同质数的乘积,求较大的那个

输入:21 → 输出:7

提示:从 2 开始枚举,找到第一个能整除 n 的数 i,n/i 就是较大的质数。
查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    for(int i = 2; i < n; i++){
        if(n % i == 0){
            cout << n / i << endl;
            break;
        }
    }
}

思路:从 2 开始从小到大找第一个能整除 n 的数,它就是较小的质数,n / i 就是较大的那个。

易错:找到答案后忘记 break 继续空转;或误把较小的质数 i 当成答案输出。

B2闰年统计

统计 2000~2050 年间有多少个闰年

输出:13

提示:闰年 = 能被4整除且不能被100整除,或能被400整除。
查看参考答案
#include <iostream>
using namespace std;
int main(){
    int cnt = 0;
    for(int y = 2000; y <= 2050; y++){
        if((y%4==0 && y%100!=0) || y%400==0){
            cnt++;
            cout << y << " ";
        }
    }
    cout << "\n共 " << cnt << " 个闰年" << endl;
}

思路:让年份从 2000 循环到 2050,逐年套用闰年条件判断并计数。

易错:只写 y % 4 == 0,漏掉「整百年必须能被 400 整除」这一条。

B3数字反转

输入一个正整数,输出它的反转数

输入:12345 → 输出:54321

提示:用 for 或 while 循环,每次取末位(n%10),拼到新数上。
查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, rev = 0;
    cin >> n;
    for(; n > 0; n /= 10){
        rev = rev * 10 + n % 10;
    }
    cout << rev << endl;
}

思路:每轮取出末位数字拼到反转数末尾(rev = rev*10 + n%10),同时把 n 去掉末位。

易错:忘记 n /= 10 造成死循环;遇到末尾带 0 的数(如 120)反转后零会消失。

B4最大跨度值

给定 n 个非负整数,求最大值与最小值之差

输入:6 3 0 8 7 5 9 → 输出:9

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, a;
    cin >> n >> a;
    int maxv = a, minv = a;  // 用第一个数作初值
    for(int i = 1; i < n; i++){
        cin >> a;
        if(a > maxv) maxv = a;
        if(a < minv) minv = a;
    }
    cout << maxv - minv << endl;
}

思路:先读第一个数作为 maxv、minv 的初值,再读剩下的 n-1 个数逐一比较。

易错:循环写成 i <= n 会多读一个数;初值若写死成 0,数据含负数时结果就错。

🔴 C 组 · 挑战(4 题)

C1连续正常血压

计算病人保持正常血压的最长连续小时数

题目描述:收缩压 90~140 且舒张压 60~90 为正常。给出 n 次测量值,求最长连续正常次数。

输入:4 100 80 90 50 120 60 140 90 → 输出:2

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n, cur = 0, ans = 0;
    cin >> n;
    for(int i = 0; i < n; i++){
        int s, d;
        cin >> s >> d;
        if(s>=90 && s<=140 && d>=60 && d<=90){
            cur++;
            if(cur > ans) ans = cur;
        } else cur = 0;
    }
    cout << ans << endl;
}

解析:连续正常则 cur++,出现异常则 cur 归零。ans 始终记录历史最大值。

易错:判断血压正常要用 && 同时满足上下限,写成 || 会把不正常的小时也算进去;中断时忘记把 cur 归零。

C2评委打分

去掉一个最高分和一个最低分,求平均分

输入:10 90 89 92 90 93 95 88 90 89 88 → 输出:90.125

查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    double a, maxv = 0, minv = 100, sum = 0;
    for(int i = 0; i < n; i++){
        cin >> a;
        sum += a;
        if(a > maxv) maxv = a;
        if(a < minv) minv = a;
    }
    cout << (sum - maxv - minv) / (n - 2) << endl;
}

思路:边读入边累加总分并记录最高分、最低分,最后用总分减掉两个极端值再除以 n-2。

易错:最后除以 n 而不是 n-2;maxv、minv 初值范围不当,遇到极端数据会统计错。

C3冰雹序列

按冰雹猜想规则迭代,输出每次变换后的值直到变为 1

输入:7 → 输出:7 22 11 34 17 52 26 13 40 20 10 5 16 8 4 2 1

提示:偶数除以2,奇数乘3加1。这道题更适合用 while 循环(次数未知)。
查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    while(n != 1){
        cout << n << " ";
        if(n % 2 == 0) n /= 2;
        else n = n * 3 + 1;
    }
    cout << 1 << endl;
}

解析:冰雹猜想的迭代次数未知,用 while 比 for 更自然。但也可以用 for(;;) 配合 break 实现。

易错:n 一开始就等于 1 时循环体一次都不执行,程序直接输出 1,很容易漏掉这个边界情况。

C4打印菱形

输入奇数 n,打印一个 n 行的菱形图案

输入:5 → 输出:

预期输出
  *
 ***
*****
 ***
  *
提示:分上半部分和下半部分,各用嵌套 for 循环控制空格和星号数量。
查看参考答案
#include <iostream>
using namespace std;
int main(){
    int n;
    cin >> n;
    int mid = n / 2;
    // 上半部分(含中间最宽行)
    for(int i = 0; i <= mid; i++){
        for(int j = 0; j < mid - i; j++) cout << " ";
        for(int j = 0; j < 2*i + 1; j++) cout << "*";
        cout << endl;
    }
    // 下半部分
    for(int i = mid - 1; i >= 0; i--){
        for(int j = 0; j < mid - i; j++) cout << " ";
        for(int j = 0; j < 2*i + 1; j++) cout << "*";
        cout << endl;
    }
}

解析:上半部分每行空格递减、星号递增;下半部分反过来。嵌套循环的经典图形题。

易错:上半部分和下半部分的行数、每行空格数算错,会多打一行或少打一行;输入 n = 1 时只应输出一个星号。