GESP三级真题 202509-P1:数组清零完整拆解,模拟法的标准写法

四季读书网 1 0
GESP三级真题 202509-P1:数组清零完整拆解,模拟法的标准写法

这道题,考的是"照着说明书做"

2025年9月GESP C++三级编程第一题「数组清零」,题目给了一套操作规则,让你模拟执行,数出总共操作了多少次。

这类题叫模拟法——题目说怎么做,代码就怎么做,一步不多一步不少。

难点不是想算法,而是把题目的文字规则,原原本本翻译成代码,并且处理好两个容易忽略的细节。


题目原文

数组清零(GESP C++ 三级,2025年9月)

小 A 有一个由 n 个非负整数构成的数组。他会对数组重复进行以下操作,直到数组中只包含 0

  1. 找出值最大的元素,若有多个最大值,选其中下标最大的,记为位置 k
  2. 在所有非零元素里,找到值最小的元素
  3. 令 a[k] = a[k] - 最小值,操作次数加 1

请输出总操作次数。

样例输入 1:

  1. 3
  2. 234

样例输出 1:

  1. 7

过程演示: [2,3,4] → [2,3,2] → [2,1,2] → [2,1,1] → [1,1,1] → [1,1,0] → [1,0,0] → [0,0,0]

样例输入 2:

  1. 5
  2. 13225

样例输出 2:

  1. 13

数据范围: 1 ≤ n ≤ 100,0 ≤ a[i] ≤ 100


家长速览

本篇核心: while(1) 主循环模拟每轮操作;找最大值用 >=(多个相等取下标最大);找最小值加 a[i]>0 过滤零;终止条件是最大值为 0。


第一步:读懂题,手算样例

拿样例 [2, 3, 4] 手算,逐步模拟:

轮次
数组状态
最大值位置 k
非零最小值
操作
1
[2, 3, 4]
k=3(值4)
min=2
a[3]=4-2=2
2
[2, 3, 2]
k=2(值3)
min=2
a[2]=3-2=1
3
[2, 1, 2]
k=3(值2,下标最大)
min=1
a[3]=2-1=1
4
[2, 1, 1]
k=1(值2)
min=1
a[1]=2-1=1
5
[1, 1, 1]
k=3(值1,下标最大)
min=1
a[3]=1-1=0
6
[1, 1, 0]
k=2(值1,下标最大)
min=1
a[2]=1-1=0
7
[1, 0, 0]
k=1(值1)
min=1
a[1]=1-1=0

操作 7 次,数组变为 [0,0,0],与样例吻合。

手算完再写代码,思路更清晰。

GESP三级真题 202509-P1:数组清零完整拆解,模拟法的标准写法 第1张

第二步:难点在哪里

难点一:找最大值,为什么用 >= 而不是 >

题目说"多个最大值取下标最大的那个"。

  • 用 >:遇到相等不更新,最后留下的是下标最小的最大值
  • 用 >=:遇到相等也更新,最后留下的是下标最大的最大值
  1. int mx =1;
  2. for(int i =1; i <= n; i++)
  3. if(a[i]>= a[mx]) mx = i;// >= ,相等也更新

第 3 轮手算里, [2,1,2] 的最大值是 2,位置 1 和位置 3 都是 2,用 >= 才能拿到位置 3。

难点二:找最小值,为什么要过滤零?

题目说"在所有非零元素里找最小值"。

如果不过滤,数组里已经变成 0 的元素会被当成最小值,然后每轮 a[mx]-=0,数组永远不会变化——程序死循环

  1. int mn = a[mx];// 初值用当前最大值
  2. for(int i =1; i <= n; i++)
  3. if(a[i]>0) mn = min(mn, a[i]);// 只看非零元素

这两个细节,是这道题考场上最常见的失分点。


第三步:破题思路

  1. cnt =0
  2. while数组不全为0
  3. 找最大值位置 k(相等取下标最大,用>=)
  4. 如果 a[k]==0,退出循环
  5. 找非零元素里的最小值 mn(过滤零)
  6.     a[k]-= mn
  7.     cnt++
  8. 输出 cnt

这就是 SM-07 模拟法的六步框架:圈出状态变量( a[k] 和 cnt)→ 初始化 → 写主循环 → 写终止条件 → 检查边界 → 输出。


动手填一填:程序填空

GESP三级真题 202509-P1:数组清零完整拆解,模拟法的标准写法 第2张
  1. #include<algorithm>
  2. #include<cstdio>
  3. usingnamespace std;
  4. constint N =105;
  5. int n, a[N], cnt;
  6. int main(){
  7.     cnt =0;
  8.     scanf("%d",&n);
  9. for(int i =1; i <= n; i++) scanf("%d",&a[i]);
  10. while(1){
  11. // 找最大值,多个相等取下标最大
  12. int mx =1;
  13. for(int i =1; i <= n; i++)
  14. if(____________________) mx = i;// ① 更新 mx 的条件
  15. if(a[mx]==0)break;// 最大值为 0,全部清零,退出
  16. // 找非零元素里的最小值
  17. int mn = a[mx];
  18. for(int i =1; i <= n; i++)
  19. if(____________________) mn = min(mn, a[i]);// ② 只看非零元素
  20.         ____________________;// ③ 执行操作
  21.         cnt++;
  22. }
  23.     printf("%d\n", cnt);
  24. return0;
  25. }
考的是什么
答案
多个最大值取下标最大
a[i]>=a[mx]
过滤零元素
a[i]>0
最大值元素减去最小值
a[mx]-=mn;

这道题考察的核心能力

能力点
说明
SM-07 模拟法编程
按规则重复操作,直到满足终止条件
找最大值取下标最大
>=
 而不是 >,遇到相等也更新
最值初值用数组元素
mn=a[mx]
,不能用 0 或随意猜一个数
非零元素过滤
a[i]>0
 防止把 0 当最小值,避免死循环

同类题练一练

洛谷 P1009「阶乘之和」

循环迭代类模拟题,每轮计算当前阶乘并累加,直到满足条件退出。和数组清零一样,关键是初始化和终止条件写准。


小结

「数组清零」的核心是两个细节:

  1. 找最大值用 >=:遇到相等也更新,保证取到下标最大的那个
  2. 找最小值过滤零:加 a[i]>0,不然零会变成最小值,程序死循环

这两个地方写对,模拟过程照着题目规则翻译,就能拿满分。

抱歉,评论功能暂时关闭!