#P1501. 2026 CSP-S1 第一轮真题卷
2026 CSP-S1 第一轮真题卷
2026 CSP-S1 第一轮真题卷
2026 CCF 非专业级别软件能力认证第一轮(CSP-S1)提高级 C++ 语言试题,认证时间:2026 年 9 月 19 日 14:30~16:30,满分 100 分。
一、单项选择题(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
第 1 题
执行下列代码后,cnt 的值是( )
01 int x = 2026, cnt = 0;
02 while (x) {
03 x &= x - 1;
04 cnt++;
05 }
{{ select(1) }}
- 6
- 7
- 11
- 8
第 2 题
用权值 构造哈夫曼树,其带权路径长度是( )
{{ select(2) }}
- 108
- 96
- 99
- 102
第 3 题
把 1 到 1000 的所有整数按十进制写出,数字「1」总共出现了多少次( )
{{ select(3) }}
- 300
- 271
- 301
- 320
第 4 题
将 5 封信随机装入 5 个写好地址的信封(每封一个),恰好有 2 封装对的方案数是( )
{{ select(4) }}
- 44
- 24
- 10
- 20
第 5 题
的值是( )
{{ select(5) }}
- 29
- 9
- 43
- 81
第 6 题
有 5 堆石子排成一行,重量依次为 4, 1, 3, 2, 5。每次只能把相邻的两堆合并成一堆,代价为这两堆重量之和。将所有石子合并成一堆的最小总代价是( )
{{ select(6) }}
- 36
- 35
- 34
- 33
第 7 题
树状数组维护长度 的序列。查询前缀和 sum(11) 与单点修改 add(3, x) 分别需要访问树状数组中多少个下标( )
{{ select(7) }}
- 3 和 4
- 4 和 4
- 3 和 5
- 4 和 3
第 8 题
有向无环图 的顶点集为 ,边集为 ,顶点 4 与任何顶点均不相邻。该图不同的拓扑序共有多少种( )
{{ select(8) }}
- 12
- 8
- 4
- 6
第 9 题
某分治算法满足 ,,则 是( )
{{ select(9) }}
第 10 题
无根树含 9 个结点(编号为 1—9),边集为 $\{(1,2), (1,3), (2,4), (2,5), (3,6), (6,7), (7,8), (5,9)\}$。该树的直径(以边数计)与重心分别是( )
{{ select(10) }}
- 直径 6,重心为结点 3
- 直径 7,重心为结点 2
- 直径 8,重心为结点 1
- 直径 7,重心为结点 1
第 11 题
一张有向图缩点后得到的有向无环图含 6 个顶点,其中入度为 0 的顶点有 3 个、出度为 0 的顶点有 4 个。为使原图变成强连通图,至少需要添加多少条有向边( )
{{ select(11) }}
- 7
- 6
- 4
- 3
第 12 题
含 6 个结点的不同形态的二叉树共有多少棵(结点不带标号,区分左右子树)( )
{{ select(12) }}
- 42
- 429
- 132
- 720
第 13 题
字符串 ,其所有既是真前缀又是真后缀的子串(非空)的长度之和是( )
{{ select(13) }}
- 4
- 6
- 7
- 5
第 14 题
用归并排序统计逆序对,合并部分的核心代码如下。若把判断条件中的 a[i] <= a[j] 改成 a[i] < a[j],则 ans 统计出的结果是( )
01 // 归并 a[l..mid] 与 a[mid+1..r],同时累加逆序对
02 if (a[i] <= a[j]) {
03 tmp[k++] = a[i++]; // 取左半段元素
04 } else {
05 tmp[k++] = a[j++]; // 取右半段元素
06 ans += mid - i + 1;
07 }
{{ select(14) }}
- 完全不变
- 变为原来的两倍
- 变为满足 且 的数对个数
- 变为原来的一半
第 15 题
执行 power(2, 100, 1000) 调用下列函数,返回值是( )
01 long long power(long long a, long long b, long long p) {
02 long long r = 1 % p;
03 while (b) {
04 if (b & 1)
05 r = r * a % p;
06 a = a * a % p;
07 b >>= 1;
08 }
09 return r;
10 }
{{ select(15) }}
- 576
- 376
- 976
- 176
二、阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填 ,错误填 ;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分)
(1)模 2 除法(CRC 求余)
01 #include <iostream>
02 #include <string>
03 using namespace std;
04 int a[100];
05 string s;
06 int gen[13] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};
07 int main() {
08 cin >> s;
09 for (int i = 0; i < 32; ++i) {
10 a[i] = s[i] - '0';
11 }
12 for (int i = 32; i < 44; ++i) {
13 a[i] = 0;
14 }
15 for (int i = 0; i < 32; ++i) {
16 if (a[i] == 0) continue;
17 for (int j = 0; j < 13; ++j) {
18 a[i + j] ^= gen[j];
19 }
20 }
21 for (int i = 32; i < 44; ++i) {
22 cout << a[i];
23 }
24 cout << endl;
25 return 0;
26 }
说明:输入保证为一个长度恰为 32 的 '0'/'1' 字符串。
判断题
第 16 题
( 分)当输入为 32 个 '0' 时,程序输出 12 个 0。
{{ input(16) }}
第 17 题
程序运行结束后,数组 a 中下标从 0 到 31 的元素一定全部为 0。
{{ input(17) }}
第 18 题
若将第 12~14 行(为 a[32] 到 a[43] 补 0 的循环)删除,会改变程序输出结果。
{{ input(18) }}
单选题
第 19 题
关于第 6 行定义的数组 gen,下列说法正确的是( )。
{{ select(19) }}
gen共有 12 个元素,表示一个 12 位的除数gen共有 13 个元素,表示一个 13 位的被除数gen共有 13 个元素,其中gen[0]是除数的最高位gen共有 13 个元素,其中gen[12]是除数的最高位
第 20 题
该程序实现的功能,最准确的说法是( )。
{{ select(20) }}
- 将输入的 32 位串看成二进制数 ,输出 与 13 位二进制数 1100000001111 按位异或的结果
- 将输入串视为 32 位二进制数 ,在其后补 12 个
0(即计算 ),再对它用 1100000001111 作模 2 除法求余数,并输出 12 位余数 - 对输入的 32 位串逐位取反并输出结果
- 统计输入串中 1 的个数,并把该个数用 12 位二进制表示后输出
第 21 题
若将第 16 行 if (a[i] == 0) continue; 删除,说法正确的是( )。
{{ select(21) }}
- 程序输出的结果不会改变
- 可能造成程序运行错误
- 程序能够正常输出一个 12 位
'0'/'1'串,但是输出结果与输入的s无关 - 程序运行结束后,
a[0]的值一定为 0
(2)稀疏表求区间 GCD
01 #include <iostream>
02 using namespace std;
03 int n, m, a[100007], L, R, lg[100007], i, j, t, dp[100007][25], pw[25];
04 int gcd(int x, int y) {
05 if (y == 0) return x;
06 return gcd(y, x % y);
07 }
08 int main() {
09 cin >> n >> m;
10 for (i = 1; i <= n; i++) cin >> a[i];
11 t = 0;
12 pw[0] = 1;
13 for (i = 1; i <= 24; i++) pw[i] = pw[i - 1] * 2;
14 for (i = 1; i <= 100000; i++)
15 if (pw[t + 1] > i) lg[i] = t;
16 else t++, lg[i] = t;
17 for (i = 1; i <= n; i++)
18 dp[i][0] = a[i];
19 for (j = 1; j <= lg[n]; j++)
20 for (i = 1; i + pw[j] - 1 <= n; i++) {
21 dp[i][j] = gcd(dp[i][j - 1], dp[i + pw[j - 1]][j - 1]);
22 }
23 for (i = 1; i <= m; i++) {
24 cin >> L >> R;
25 cout << gcd(dp[L][lg[R - L + 1]], dp[R - pw[lg[R - L + 1]] + 1][lg[R - L + 1]]) << endl;
26 }
27 return 0;
28 }
说明:保证 ,每次查询满足 ,且数组 中的元素均为正整数。
判断题
第 22 题
当 ,,且仅有一次查询 、 时,输出为 1。
{{ input(22) }}
第 23 题
当某次查询的区间长度为 1(即 )时,这次查询的输出一定等于 。
{{ input(23) }}
第 24 题
任意一次查询的输出结果一定不小于该查询区间内的最小值。
{{ input(24) }}
单选题
第 25 题
对于 ,数组 dp[i][j] 保存的是( )。
{{ select(25) }}
- 从
a[i]开始连续 个数的最大公约数 - 从
a[i]开始连续 个数的最大公约数 a[i]与a[j]的最大公约数- 从
a[1]到a[i]的最大公约数
第 26 题
若把一次求最大公约数的运算视为 ,则第 17~22 行建表过程的时间复杂度为( )。
{{ select(26) }}
第 27 题
设 为一次查询的区间长度(即 ),则使得 lg[x] = 5 的 的取值范围是( )。
{{ select(27) }}
(3)树形 DP 求直径
01 #include <iostream>
02 using namespace std;
03 int n, fa[100007], f[100007], ans;
04 int main() {
05 cin >> n;
06 for (int i = 2; i <= n; ++i) {
07 cin >> fa[i];
08 }
09 for (int i = n; i >= 2; --i) {
10 if (f[fa[i]] + f[i] + 1 > ans) {
11 ans = f[fa[i]] + f[i] + 1;
12 }
13 if (f[i] + 1 > f[fa[i]]) {
14 f[fa[i]] = f[i] + 1;
15 }
16 }
17 cout << ans << endl;
18 return 0;
19 }
说明:输入第一行为结点个数 ,第二行为 个整数,依次表示结点 的父结点编号,满足 且 ,根结点为 1。
判断题
第 28 题
当 ,fa[2]~fa[5] = 时,程序输出 4。
{{ input(28) }}
第 29 题
程序输出前,f[1] 的值一定等于 ans 的值。
{{ input(29) }}
第 30 题
将第 10~12 行与第 13~15 行两个 if 语句的顺序交换后,程序的输出结果不受影响。
{{ input(30) }}
单选题
第 31 题
程序输出的 ans 表示的是( )。
{{ select(31) }}
- 树中距离最远的两个结点之间路径所经过的边数
- 根结点 1 到最远叶子结点之间路径所经过的边数
- 树中叶子结点的个数
- 所有结点的父结点编号之和
第 32 题
当 ,fa[2]~fa[7] = 时,输出为( )。
{{ select(32) }}
- 2
- 3
- 4
- 5
第 33 题
当 ,满足输出为 9 的合法输入种类数为( )。
{{ select(33) }}
- 0
- 9
- 256
- 512
三、完善程序(单选题,每小题 3 分,共计 30 分)
(1)平衡路线
给定一张有 个顶点、 条边的无向图,每条边带有符号 + 或 -。对于一条从顶点 到顶点 的路线,允许重复经过顶点和边,定义一条路线的权值如下:记 、 分别为经过的 + 边数和经过的 - 边数,则该路线的权值为 。
请计算从 到 的路线的最小权值。若不存在从 到 的路线,则输出 。
输入第一行为四个整数 。接下来 行,每行给出两个整数 和一个字符 + 或 -,描述一条连接 与 的无向边及其符号。
数据满足 ,, 且 ,,可能出现重边。
01 #include <iostream>
02
03 constexpr int N = 200005;
04 constexpr int M = 400005;
05
06 int n, m, s, t;
07 int h[N], e[M << 1], ne[M << 1], w[M << 1], idx;
08 int q[N], d[N], c[N];
09
10 void add(int a, int b, int z) {
11 e[idx] = b;
12 w[idx] = z;
13 ne[idx] = h[a];
14 h[a] = idx++;
15 }
16
17 int main() {
18 std::cin >> n >> m >> s >> t;
19 for (int i = 1; i <= n; i++)
20 h[i] = d[i] = c[i] = -1;
21 for (int i = 0; i < m; i++) {
22 int a, b;
23 char op[2];
24 std::cin >> a >> b >> op;
25 int z = ①;
26 add(a, b, z);
27 add(b, a, z);
28 }
29 int hh = 0, tt = 0;
30 int p = 0, ng = 0, ok = 1;
31 q[tt++] = s;
32 d[s] = c[s] = 0;
33 while (②) {
34 int x = q[hh++];
35 for (int i = h[x]; i != -1; i = ne[i]) {
36 int y = e[i];
37 if (w[i] > 0) p = 1;
38 if (w[i] < 0) ng = 1;
39 if (d[y] == -1) {
40 d[y] = ③;
41 c[y] = c[x] ^ 1;
42 q[tt++] = y;
43 } else if (④)
44 ok = 0;
45 }
46 }
47 if (d[t] == -1) {
48 std::cout << -1;
49 return 0;
50 }
51 if (!p || !ng) {
52 std::cout << d[t];
53 return 0;
54 }
55 if (⑤) std::cout << 0;
56 else std::cout << 1;
57 return 0;
58 }
第 34 题
①处应填( )
{{ select(34) }}
op[0] == '+' ? 0 : 1op[0] == '+'op[0] == '+' ? 1 : -1op[0] == '-' ? 1 : 0
第 35 题
②处应填( )
{{ select(35) }}
hh < ntt < nhh <= tthh < tt
第 36 题
③处应填( )
{{ select(36) }}
d[y] + 1d[x] + 1d[x]d[x] - 1
第 37 题
④处应填( )
{{ select(37) }}
c[y] == c[x]w[i] == 1c[y] != c[x]d[y] + 1 != d[x]
第 38 题
⑤处应填( )
{{ select(38) }}
ok && c[s] == c[t]ok && c[s] != c[t]!ok || c[s] == c[t]!ok && c[s] != c[t]
(2)标准答案
有 名学生参加一次考试,考试共有 道选择题,每道题只有 A、B 两个选项。第 名学生的作答用一个长度为 的字符串 表示。若最终公布的标准答案与该学生在某道题上的作答相同,则该学生得 1 分,否则不得分。记第 名学生最终得到的总分为 。
给定每名学生的目标分数 。现在需要构造一份标准答案,使 尽可能大。
数据满足 ,,。
以下程序从枚举符号的角度处理 ,把它写成更易优化的形式。对于非零整数 ,__builtin_ctzll(x) 返回 的二进制表示末尾连续 0 的个数,__builtin_popcountll(x) 返回 的二进制表示中 1 的个数。程序输出一组满足要求的标准答案。
01 #include <cstdlib>
02 #include <iostream>
03 #include <string>
04 #include <vector>
05
06 using namespace std;
07
08 typedef long long ll;
09 typedef unsigned long long ull;
10
11 int main() {
12 int n, m;
13 cin >> n >> m;
14 vector<ll> x(n), c(n);
15 for (int i = 0; i < n; i++) {
16 cin >> x[i];
17 c[i] = ①;
18 }
19 vector<string> a(n);
20 for (int i = 0; i < n; i++)
21 cin >> a[i];
22
23 vector<int> s(n, -1);
24 vector<ll> q(m, 0);
25 ll C = 0, S = 0;
26 for (int i = 0; i < n; i++) {
27 C -= c[i];
28 for (int j = 0; j < m; j++) {
29 if (a[i][j] == 'A') q[j]--;
30 else q[j]++;
31 }
32 }
33 for (int j = 0; j < m; j++) S += abs(q[j]);
34
35 ll ans = C + S;
36 ull best = 0, lst = 0;
37
38 for (ull mask = 1; mask < (1ULL << n); mask++) {
39 ull g = ②;
40 ull d = g ^ lst;
41 int k = ③;
42 C -= ④;
43 for (int j = 0; j < m; j++) {
44 ll old = q[j];
45 int v = (a[k][j] == 'A' ? 1 : -1);
46 q[j] -= 2ll * s[k] * v;
47 S += abs(q[j]) - abs(old);
48 }
49 s[k] = -s[k];
50 if (C + S > ans) {
51 ans = C + S;
52 best = g;
53 }
54 lst = g;
55 }
56
57 for (int i = 0; i < n; i++) {
58 if (best >> i & 1) s[i] = 1;
59 else s[i] = -1;
60 }
61
62 string res(m, 'A');
63 for (int j = 0; j < m; j++) {
64 ll v = 0;
65 for (int i = 0; i < n; i++) {
66 if (a[i][j] == 'A') v += s[i];
67 else v -= s[i];
68 }
69 if (⑤) res[j] = 'A';
70 else res[j] = 'B';
71 }
72 cout << res << endl;
73 return 0;
74 }
第 39 题
①处应填( )
{{ select(39) }}
2 * x[i] - m-m + 2 * x[i] + 1m - 2 * x[i]m + 2 * x[i]
第 40 题
②处应填( )
{{ select(40) }}
mask | (mask >> 1)mask ^ (mask >> 1)mask & (mask >> 1)mask ^ ((mask >> 1) + 1)
第 41 题
③处应填( )
{{ select(41) }}
__builtin_ctzll(d) + 1__builtin_popcountll(d)__builtin_ctzll(g)__builtin_ctzll(d)
第 42 题
④处应填( )
{{ select(42) }}
2ll * s[k] * c[k]s[k] * c[k]2ll * (s[k] - c[k])2ll * c[k]
第 43 题
⑤处应填( )
{{ select(43) }}
v >= (n & 1)v > (n & 1)v + (n & 1) >= 0v * (n & 1) >= 0