CSP-J 2024 知识点精讲(下篇)
下篇聚焦 2024 年 CSP-J 入门级第一轮阅读程序题(第 16-26 题)。这一部分共涉及两道程序,分值 22 分,重点考查同学们对算法逻辑、程序执行流程以及边界条件的理解能力。
一、阅读程序题知识点总览
二、程序(1):素数统计
程序代码
#include <iostream> using namespace std; bool isPrime(int n) { if (n <= 1) return false; for (int i = 2; i * i <= n; i++) { if (n % i == 0) return false; } return true; } int countPrimes(int n) { int count = 0; for (int i = 2; i <= n; i++) { if (isPrime(i)) count++; } return count; } int sumPrimes(int n) { int sum = 0; for (int i = 2; i <= n; i++) { if (isPrime(i)) sum += i; } return sum; } int main() { int x; cin >> x; cout << countPrimes(x) << " " << sumPrimes(x) << endl; return 0; } 功能说明
isPrime(n) | |
countPrimes(n) | |
sumPrimes(n) |
第 16 题:输入 10 时的输出
答案:√
2~10 中的素数为:2、3、5、7
素数个数:4 素数之和:2 + 3 + 5 + 7 = 17
程序输出 4 17,判断正确。
第 17 题:修改 isPrime 条件后的输出
答案:×
题目说:将 i * i <= n 改为 i <= n/2,输入 20 时 countPrimes(20) 的输出变为 6。
分析:
修改循环条件只会降低效率,不会改变正确性 20 以内的素数:2、3、5、7、11、13、17、19,共 8 个 所以输出应为 8,不是 6
核心知识点:优化条件不影响算法正确性
i * i <= n 只是提前终止循环,只要 n 有约数,在 sqrt(n) 之前一定能找到。
第 18 题:sumPrimes 函数功能
答案:√
sumPrimes(n) 遍历 2~n,将素数累加,确实计算 2~n 所有素数之和。
第 19 题:输入 50 时 sumPrimes 的输出
答案:B. 328
2~50 的素数:2、3、5、7、11、13、17、19、23、29、31、37、41、43、47
求和:2+3+5+7+11+13+17+19+23+29+31+37+41+43+47 = 328
第 20 题:循环条件修改的影响
答案:A. 将不能正确计算 10 以内素数个数及其和
分析:
将 i * i <= n 改为 i <= n 后,isPrime 会枚举到 i = n。
由于任何数 n % n == 0,所以所有数都会被判定为合数,程序无法正确统计素数。
核心知识点:循环边界的重要性
边界条件错误会直接导致算法结果错误,阅读程序时一定要仔细分析循环终止条件。
三、程序(2):上楼梯最小花费
程序代码
#include <iostream> #include <vector> using namespace std; int compute(vector<int> &cost) { int n = cost.size(); vector<int> dp(n + 1, 0); dp[1] = cost[0]; for (int i = 2; i <= n; i++) { dp[i] = min(dp[i - 1], dp[i - 2]) + cost[i - 1]; } return min(dp[n], dp[n - 1]); } int main() { int n; cin >> n; vector<int> cost(n); for (int i = 0; i < n; i++) { cin >> cost[i]; } cout << compute(cost) << endl; return 0; } 功能说明
这是一个经典的动态规划问题:
有一组台阶,每级台阶有一个花费 cost[i]。每次可以跨 1 级或 2 级,求从地面到达顶部的最小花费。dp[i] 表示到达第 i 级台阶的最小花费。
状态转移方程:
dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1] 最后返回 min(dp[n], dp[n-1]),因为最后一步可能跨 1 级或 2 级到达顶部。
第 21 题:cost = {10, 15, 20} 的输出
答案:√
最优路径:地面 → 第 2 级 → 顶部
花费:15
所以输出为 15,判断正确。
第 22 题:数组越界与编译错误
答案:×
将 dp[i-1] 改为 dp[i-3]:
- 不会产生编译错误
:语法上 dp[i-3]是合法的数组访问 - 会产生运行错误
:当 i = 2时,dp[-1]越界
核心知识点:编译错误 vs 运行错误
编译错误:语法问题,程序无法编译 运行错误:逻辑问题,程序运行时报错或异常
第 23 题:程序是否输出最小元素
答案:×
程序输出的是"从地面到顶部的最小总花费",不是 cost 数组中的最小元素。
例如 cost = {10, 15, 20},最小元素是 10,但程序输出 15。
第 24 题:cost = {1,100,1,1,1,100,1,1,100,1} 的输出
答案:A. 6
最优路径:走花费为 1 的台阶,避开 100 的台阶。
走过的台阶:第 1、3、5、7、8、10 级,每个花费 1。
总花费:1 + 1 + 1 + 1 + 1 + 1 = 6
第 25 题:cost = {10,15,30,5,5,10,20} 的输出
答案:B. 30
最优路径:地面 → 第 2 级(15) → 第 4 级(5) → 第 6 级(10) → 顶部
总花费:15 + 5 + 10 = 30
第 26 题:修改状态转移方程后的输出
答案:A. 10
修改后代码变为:
dp[i] = dp[i-1] + cost[i-2]; 代入 cost = {5, 10, 15}:
dp[0] = 0dp[1] = cost[0] = 5dp[2] = dp[1] + cost[0] = 5 + 5 = 10dp[3] = dp[2] + cost[1] = 10 + 10 = 20
最终返回 min(dp[3], dp[2]) = min(20, 10) = 10
核心知识点:状态转移方程决定 DP 含义
一个微小的改动就可能改变整个 DP 的含义,阅读程序时要逐行跟踪状态变化。
四、下篇知识点清单
1. 素数算法
素数判定:试除法 试除法优化:枚举到 √n 循环边界对结果的影响 素数个数统计与素数和
2. 动态规划入门
DP 状态定义: dp[i]表示到达第 i 级台阶的最小花费状态转移方程: dp[i] = min(dp[i-1], dp[i-2]) + cost[i-1]边界条件: dp[0] = 0,dp[1] = cost[0]最终结果: min(dp[n], dp[n-1])
3. 程序阅读技巧
先读函数名和主函数,把握整体功能 再逐行跟踪变量变化 注意数组下标是否越界 区分编译错误和运行错误 循环边界条件改变会产生什么影响
五、2024 年 CSP-J 第一轮整体备考建议
1. 时间分配
选择题(1-15):建议 20-25 分钟 阅读程序题(16-32):建议 35-40 分钟 完善程序题(33-42):建议 25-30 分钟
2. 重点突破方向
- 计算机基础
:进制转换、存储单位、ASCII 码、操作系统常识 - 数据结构
:栈、队列、二叉树、图的基础性质 - 算法思维
:二分、递归、动态规划初步 - C++ 语法
:数据类型、循环、数组、函数、递归
3. 刷题建议
近 5 年 CSP-J 初赛真题至少刷 2 遍 每道题不仅要知道答案,还要能说出对应知识点 建立个人错题本,按知识点分类整理
上篇回顾:第 1-15 题知识点精讲已发布,包含整数表示、进制转换、图论、树遍历、排列组合等核心内容。
祝同学们备考顺利,初赛高分通过!
夜雨聆风