












2023 年 CCF 非专业级软件能力认证(CSP-J/S 2023)第一轮认证于 2023 年 9 月 16 日举行。继上一篇单项选择题解析后,本文为您带来 第二部分:阅读程序题(共 3 大题,计 40 分) 的逐题源码分析、算法推演与深度全解析。
阅读程序题主要考查对 C++ 格式化输出、海伦公式、动态规划最长公共子序列(LCS)、字符串匹配与移位、试除法分解约数及数论性质 等知识点的掌握。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include<iostream>
#include<cmath>
using namespace std;
double f(double a,double b,double c){
double s=(a+b+c)/2;
return sqrt(s*(s-a)*(s-b)*(s-c));
}
int main(){
cout.flags(ios::fixed);
cout.precision(4);
int a,b,c;
cin>>a>>b>>c;
cout<<f(a,b,c)<<endl;
return 0;
}
假设输入的所有数都是不超过 1000 的正整数,完成下面的判断题和单选题:
本程序核心在于通过 海伦公式(Heron’s Formula) 计算边长分别为 $a, b, c$ 的三角形面积:
f(a, b, c) 函数:先计算半周长 $s = \frac{a+b+c}{2}$,随后使用公式 $S = \sqrt{s(s-a)(s-b)(s-c)}$ 计算并返回三角形面积。main 函数:cout.flags(ios::fixed) 与 cout.precision(4) 组合使用,控制标准输出流以 定点小数格式(fixed-point) 精确保留 4 位小数。f(a,b,c) 并输出计算结果。2 2 2 时,输出为 1.7321 ( )A. 正确
B. 错误
正确答案: A
深度解析:
当 $a = 2, b = 2, c = 2$ 时,该三角形为边长为 2 的等边三角形。
1.7321。 因此本题说法正确。(s-b)*(s-c) 改为 (s-c)*(s-b) 不会影响程序运行的结果 ( )A. 正确
B. 错误
正确答案: A
深度解析:
在实数乘法运算中,乘法满足 交换律,即对任意实数 $x, y$,均有 $x \times y = y \times x$。 因此,将 (s-b)*(s-c) 改写为 (s-c)*(s-b) 表达式的代数含义和数值计算结果完全一致,不会对程序运行结果产生任何影响。故本题说法正确。
A. 正确
B. 错误
正确答案: A
深度解析:
在 C++ iostream 中:
cout.flags(ios::fixed) 强制浮点数采用定点小数表示法输出;cout.precision(4) 设置浮点数的显示精度为 4 位。 两者结合后,即使计算结果为整数(如 6 或 30),cout 也会在末尾自动补零输出 6.0000 或 30.0000。由于题目假设输入的数均为不超过 1000 的正整数,输出始终为浮点数且固定展示 4 位小数。因此本题说法正确。3 4 5 时,输出为 ( )A.
6.0000
B.12.0000
C.24.0000
D.30.0000
正确答案: A
深度解析:
$3, 4, 5$ 是一组经典的勾股数,构成的三角形为直角三角形(直角边长为 3 和 4)。
6.0000。5 12 13 时,输出为 ( )A.
24.0000
B.30.0000
C.60.0000
D.120.0000
正确答案: B
深度解析:
$5, 12, 13$ 同样是一组标准的勾股数($5^2 + 12^2 = 25 + 144 = 169 = 13^2$),构成的三角形为直角三角形(直角边长为 5 和 12)。
30.0000,对应 B 选项。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;
int f(string x,string y){
int m=x.size();
int n=y.size();
vector<vector<int>>v(m+1,vector<int>(n+1,0));
for(int i=1;i<=m;i++){
for(int j=1;j<=n;j++){
if(x[i-1]==y[j-1]){
v[i][j]=v[i-1][j-1]+1;
}else{
v[i][j]=max(v[i-1][j],v[i][j-1]);
}
}
}
return v[m][n];
}
bool g(string x,string y){
if(x.size() != y.size()){
return false;
}
return f(x+x,y)==y.size();
}
int main(){
string x,y;
cin>>x>>y;
cout<<g(x,y)<<endl;
return 0;
}
f(x, y) 函数:这是求解 最长公共子序列(Longest Common Subsequence, LCS) 的经典动态规划算法。m 和 n 分别为字符串 x 和 y 的长度。v[i][j] 表示 x[0...i-1] 与 y[0...j-1] 的最长公共子序列长度。x[i-1] == y[j-1],则 v[i][j] = v[i-1][j-1] + 1;否则 v[i][j] = max(v[i-1][j], v[i][j-1])。v[m][n],即 x 和 y 的 LCS 长度。g(x, y) 函数:x 与 y 长度是否相等,若不等直接返回 false。f(x+x, y)。将 x 拼接自身得到 x+x(长度为 $2m$),若 y 是 x+x 的一个子序列且长度等于 y.size(),则返回 true。f 函数的返回值小于等于 $\min{n, m}$。( )A. 正确
B. 错误
正确答案: A
深度解析:
f(x, y) 计算的是字符串 x(长度 $m$)和 y(长度 $n$)的 最长公共子序列长度。 公共子序列中的字符必定来自原字符串,其长度不可能超过参与比较的任何一个字符串的长度。因此 LCS 长度的上界为 $\min{m, n}$,本题说法正确。
f 函数的返回值等于两个输入字符串的最长公共子串的长度。( )A. 正确
B. 错误
正确答案: B
深度解析:
在数据结构与算法中:
x[i-1] != y[j-1] 时,使用了 v[i][j] = max(v[i-1][j], v[i][j-1]) 继承前面的历史匹配状态,这正是 最长公共子序列 的状态转移方程。因此说法错误。g 函数的返回值总是 true。( )A. 正确
B. 错误
正确答案: A
深度解析:
当输入 $x$ 与 $y$ 完全相同(即 $x = y$ 且 $m = n$)时:
false。f(x+x, y) == y.size() 恒成立,g 函数必然返回 true。故本题说法正确。v[m][n] 替换为 v[n][m],那么该程序( )。A. 行为不变
B. 只会改变输出
C. 一定异常退出
D. 可能异常退出
正确答案: D
深度解析:
在 f(x, y) 函数内部,二维动态数组 v 声明大小为 v(m+1, vector<int>(n+1, 0)),即共有 $m+1$ 行、$n+1$ 列:
当我们将返回值改为 v[n][m] 时:
v[n][m] 而非答案所在的 v[m][n]),导致输出错误答案。综合以上两种情况,该程序表现为 “可能异常退出”,故选 D。
csp-j p-jcs 时,输出为( )。A.
0
B.1
C.T
D.F
正确答案: B
深度解析:
"csp-j"(长度 5),$y =$ "p-jcs"(长度 5)。长度相等。"csp-jcsp-j"。"csp-jcsp-j" 中寻找 $y =$ "p-jcs" 的每个字符:'p':出现在 x+x 下标 2 处(cs[p]-jcsp-j)'-':出现在 x+x 下标 3 处(csp[-]jcsp-j)'j':出现在 x+x 下标 4 处(csp-[j]csp-j)'c':出现在 x+x 下标 5 处(csp-j[c]sp-j)'s':出现在 x+x 下标 6 处(csp-jc[s]p-j) 按顺序依次匹配下标 $2 \rightarrow 3 \rightarrow 4 \rightarrow 5 \rightarrow 6$,完美找到了子序列 "p-jcs"。g 函数返回 true。cout 默认将布尔值 true 打印为整数 1(false 打印为 0)。因此输出为 1。csppsc spsccp 时,输出为( )。A.
T
B.F
C.0
D.1
正确答案: D
深度解析:
"csppsc"(长度 6),$y =$ "spsccp"(长度 6)。长度相等。"csppsccsppsc"。"spsccp" 的每个字符:'s':取第 1 个字符(下标 1:c[s]ppsc...)'p':取第 2 个字符(下标 2:cs[p]psc...)'s':取第 4 个字符(下标 4:cspp[s]c...)'c':取第 5 个字符(下标 5:cspps[c]...)'c':取第 6 个字符(下标 6:csppsc[c]...)'p':取第 8 个字符(下标 8:csppsccs[p]...) 匹配到的下标序列为 $1 < 2 < 4 < 5 < 6 < 8$,成功拼出 "spsccp"。g 函数返回 true,cout 打印出 1。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <iostream>
#include <cmath>
using namespace std;
int solve1(int n){
return n*n;
}
int solve2(int n){
int sum=0;
for(int i=1;i<=sqrt(n);i++){
if(n%i==0){
if(n/i==i){
sum+=i*i;
}else{
sum+=i*i+(n/i)*(n/i);
}
}
}
return sum;
}
int main(){
int n;
cin>>n;
cout<<solve2(solve1(n))<<" "<<solve1(solve2(n))<<endl;
return 0;
}
假设输入的 $n$ 是绝对值不超过 1000 的整数,完成下面的判断题和单选题:
solve1(n) 函数:计算并返回 $n^2$。solve2(n) 函数:计算正整数 $n$ 的 所有因子的平方和。main 函数:solve2(solve1(n)),即计算 $n^2$ 的所有因子的平方和;solve1(solve2(n)),即计算 ($n$ 的所有因子的平方和)的平方。solve2 函数的作用是计算 $n$ 所有的因子的平方和( )A. 正确
B. 错误
正确答案: A
深度解析:
试除法通过循环 $1 \le i \le \sqrt{n}$,找到 $n$ 的每一对因子 $(i, n/i)$。对于每一对因子,代码分别计算了它们的平方 $i^2$ 和 $(n/i)^2$ 并进行累加。这种方法完整且不重不漏地计算了正整数 $n$ 的所有约数(因子)的平方之和。因此说法正确。
A. 正确
B. 错误
正确答案: A
深度解析:
当 $n$ 是一个完全平方数时(例如 $n = 9$,$i = 3$),满足 $n/i == i$。 若不进行第 13~14 行的特判直接执行第 16 行 sum += i*i + (n/i)*(n/i),则 $3^2$ 会被加两次(算成 $3^2 + 3^2 = 18$)。13~14 行的 if(n/i == i) sum += i*i; 正是为了去重,防止平方根因子被计算两次。故本题说法正确。
solve2(n) 的返回值为 $n^2 + 1$( )A. 正确
B. 错误
正确答案: A
深度解析:
若 $n$ 为质数(如 2, 3, 5, 7 …),根据质数的定义,其正因子有且仅有两个:$1$ 和 $n$。 因此,solve2(n) 计算的因子平方和为: \(\text{solve2}(n) = 1^2 + n^2 = n^2 + 1\) 说法完全正确。
solve2(n) 的返回值为( )A. $p^2 + p + 1$
B. $n^2 + n + 1$
C. $n^2 + 1$
D. $p^4 + 2p^2 + 1$
正确答案: B
深度解析:
若输入 $n = p^2$(其中 $p$ 为质数):
solve2(n) 返回这 3 个因子的平方和: \(\text{solve2}(n) = 1^2 + p^2 + (p^2)^2 = 1 + p^2 + p^4\)A. 大于 0
B. 大于等于 0 且不一定大于 0
C. 小于 0
D. 小于等于 0 且不一定小于 0
正确答案: D
深度解析:
我们需要比较第一项 solve2(solve1(n)) 与第二项 solve1(solve2(n)) 的大小关系。 设第一项为 $A = \text{solve2}(n^2)$,第二项为 $B = (\text{solve2}(n))^2$。
我们通过代入具体数字校验:
综上所述,差值可以等于 0(当 $n = 1$ 时),也可以小于 0(当 $n > 1$ 时)。因此差值 小于等于 0 且不一定小于 0,对应 D 选项。
5 时,输出为( )A.
651 625
B.650 729
C.651 676
D.652 625
正确答案: C
深度解析:
当输入 $n = 5$ 时:
solve2(solve1(5)):solve1(5) $= 5^2 = 25$。solve2(25):$25$ 的因子有 $1, 5, 25$。solve1(solve2(5)):solve2(5):$5$ 是质数,因子有 $1, 5$,其平方和 $= 1^2 + 5^2 = 26$。solve1(26) $= 26^2 = \mathbf{676}$。651 676。对应 C 选项。在 CSP-J 阅读程序题中,拿到高分的核心在于:
fixed + precision、bool 变量用 cout 输出的默认格式(1 或 0)、vector/数组下标越界对程序的影响等。所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP 学习专题站:GESP WIKI
"luogu-"系列题目可在洛谷题库进行在线评测。
"bcqm-"系列题目可在编程启蒙题库进行在线评测。
欢迎加入:Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答
欢迎加入:C++ GESP/CSP认证学习QQ频道,考试资源总结汇总
欢迎加入:C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。