GESP 客观题评测系统

2025 CCF CSP-J 第一轮(入门级 C++)

CSPJ-2025-R1

试卷解析总览,可直接查看每题答案与解析。

一、单项选择题

(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)

1 题(单选题2 分)

一个 3232 位无符号整数可以表示的最大值,最接近下列哪个选项?

A.
4×1094 \times 10^9
B.
3×10103 \times 10^{10}
C.
2×1092 \times 10^9
D.
2×10102 \times 10^{10}

正确答案A

解析详情

【答案】A

【考点】无符号整数范围

【解析】 3232 位无符号整数的最大值是 2321=42949672952^{32}-1=4294967295,约为 4.29×1094.29\times10^9,最接近 A。

【易错点】无符号类型没有符号位,不能按 23112^{31}-1 计算。

2 题(单选题2 分)

在 C++ 中,执行 `int x = 255; cout << (x & (x - 1));` 后,输出的结果是?

A.
255255
B.
254254
C.
128128
D.
00

正确答案B

解析详情

【答案】B

【考点】按位与运算

【解析】 255255 的低 8 位全为 1,254254 的最低位为 0;因此 `255 & 254 = 254`。

【易错点】`x & (x-1)` 清除的是最低位的 1,并不是把结果变成 0。

3 题(单选题2 分)

函数 `calc(n)` 的定义如下,则 `calc(5)` 的返回值是多少?( )

int calc(int n) {
    if (n <= 1) return 1;
    if (n % 2 == 0) return calc(n / 2) + 1;
    else return calc(n - 1) + calc(n - 2);
}
A.
55
B.
66
C.
77
D.
88

正确答案B

解析详情

【答案】B

【考点】递归函数求值

【解析】 依次有 `calc(1)=1`、`calc(2)=2`、`calc(3)=3`、`calc(4)=3`,所以 `calc(5)=calc(4)+calc(3)=6`。

【易错点】偶数分支只递归到 `n/2`,不能按普通斐波那契递推。

4 题(单选题2 分)

55 个权值 10,12,15,20,2510, 12, 15, 20, 25 构造哈夫曼树,该树的带权路径长度是多少?

A.
176176
B.
186186
C.
196196
D.
206206

正确答案B

解析详情

【答案】B

【考点】哈夫曼树带权路径长度

【解析】 依次合并 10+12=2210+12=2215+20=3515+20=3522+25=4722+25=4735+47=8235+47=82;合并值之和为 22+35+47+82=18622+35+47+82=186

【易错点】每一步都必须合并当前最小的两个权值。

5 题(单选题2 分)

在一个有向图中,所有顶点的入度之和等于所有顶点的出度之和,这个总和等于?

A.
顶点数
B.
边数
C.
顶点数 + 边数
D.
顶点数 ×2\times 2

正确答案B

解析详情

【答案】B

【考点】有向图的度数

【解析】 每条有向边给起点贡献 1 个出度、给终点贡献 1 个入度,因此入度总和与出度总和都等于边数。

【易错点】不要把入度总和与出度总和再相加后当作题目所问的总和。

6 题(单选题2 分)

55 位男生和 44 位女生中选出 44 人组成一个学习小组,要求学习小组中男生和女生都有。有多少种不同的选法?

A.
126126
B.
121121
C.
120120
D.
100100

正确答案C

解析详情

【答案】C

【考点】组合计数与容斥

【解析】 总选法为 (94)=126\binom{9}{4}=126;减去全是男生的 (54)=5\binom{5}{4}=5 和全是女生的 (44)=1\binom{4}{4}=1,得到 120120

【易错点】“男女都有”要同时排除全男和全女两种情况。

7 题(单选题2 分)

假设 a,b,ca, b, c 都是布尔变量,逻辑表达式 `(a && b) || (!c && a)` 的值与下列哪个表达式不始终相等?

A.
`a && (b || !c)`
B.
`(a || !c) && (b || !c) && (a || a)`
C.
`a && (!b || c)`
D.
`!(!a || !b) || (a && !c)`

正确答案C

解析详情

【答案】C

【考点】布尔代数

【解析】 原式可提取为 `a && (b || !c)`;A、B、D 都可化为该式,而 C 中括号内为 `!b || c`,并不恒等。

【易错点】德摩根变换时要同时翻转运算符和每个变量的真假。

8 题(单选题2 分)

已知 f[0]=1f[0] = 1, f[1]=1f[1] = 1,并且对于所有 n2n \geq 2f[n]=(f[n1]+f[n2])%7f[n] = (f[n-1] + f[n-2]) \% 7。那么 f[2025]f[2025] 的值是多少?

A.
22
B.
44
C.
55
D.
66

正确答案D

解析详情

【答案】D

【考点】递推序列的模周期

【解析】 该序列模 7 的状态对以 16 为周期,2025mod16=92025\bmod16=9;计算得 f[9]=6f[9]=6

【易错点】周期判断应基于相邻两项的状态对,不能只看某一项重复。

9 题(单选题2 分)

下列关于 C++ string 类的说法,正确的是?

A.
string 对象的长度在创建后不能改变。
B.
可以使用 + 运算符直接连接一个 string 对象和一个 char 类型的字符。
C.
string 的 length() 和 size() 方法返回的值可能不同。
D.
string 对象必须以 '\0' 结尾,且这个结尾符计入 length()。

正确答案B

解析详情

【答案】B

【考点】C++ `string`

【解析】 `string` 长度可以改变,`length()` 与 `size()` 返回相同值,并且可以直接用 `+` 连接一个 `char`。

【易错点】字符串内部可提供结尾空字符,但它不计入 `length()`。

10 题(单选题2 分)

考虑以下 C++ 函数:

void solve(int &a, int b) {
    a = a + b;
    b = a - b;
    a = a - b;
}
int main() {
    int x = 5, y = 10;
    solve(x, y);
}

在 main 函数调用 solve 后,xxyy 的值分别是?

A.
5,105,10
B.
10,510,5
C.
10,1010,10
D.
5,55,5

正确答案C

解析详情

【答案】C

【考点】引用传参与值传参

【解析】 `a` 引用 `x`,三次赋值后 `x` 变为 10;`b` 是 `y` 的副本,函数内变为 5 不会修改 `y`,所以结果为 `(10,10)`。

【易错点】只有 `a` 带 `&`,不能把该函数当成同时交换两个实参。

11 题(单选题2 分)

一个 8×88 \times 8 的棋盘,左上角坐标为 (1,1)(1,1),右下角为 (8,8)(8,8)。一个机器人从 (1,1)(1,1) 出发,每次只能向右或向下走一格。要到达 (4,5)(4,5),有多少种不同的路径?

A.
2020
B.
3535
C.
5656
D.
7070

正确答案B

解析详情

【答案】B

【考点】网格路径组合计数

【解析】 从 (1,1)(1,1)(4,5)(4,5) 需要向下 3 步、向右 4 步,共 7 步,路径数为 (73)=35\binom{7}{3}=35

【易错点】坐标差分别是 3 和 4,不是直接使用终点坐标 4 和 5。

12 题(单选题2 分)

某同学用冒泡排序对数组 {6,1,5,2,4}\{6, 1, 5, 2, 4\} 进行升序排序,请问需要进行多少次元素交换?

A.
55
B.
66
C.
77
D.
88

正确答案B

解析详情

【答案】B

【考点】冒泡排序与逆序对

【解析】 冒泡排序的交换次数等于逆序对数:6 与后面四个数形成 4 对,5 与 2、4 形成 2 对,共 6 次。

【易错点】比较次数和交换次数不是同一个量。

13 题(单选题2 分)

十进制数 72010720_{10} 和八进制数 2708270_8 的和用十六进制表示是多少?

A.
38816388_{16}
B.
3DE163DE_{16}
C.
28816288_{16}
D.
99016990_{16}

正确答案A

解析详情

【答案】A

【考点】进制转换

【解析】 2708=18410270_8=184_{10},所以 720+184=90410=38816720+184=904_{10}=388_{16}

【易错点】八进制的 270270 不能直接当作十进制 270 相加。

14 题(单选题2 分)

一棵包含 10001000 个结点的完全二叉树,其叶子结点的数量是多少?

A.
499499
B.
512512
C.
500500
D.
501501

正确答案C

解析详情

【答案】C

【考点】完全二叉树

【解析】 完全二叉树按顺序编号时,有孩子的结点为 111000/2\lfloor1000/2\rfloor,其余 1000500=5001000-500=500 个结点是叶子。

【易错点】叶子数是 n/2\lceil n/2\rceil,不要只统计最底层结点。

15 题(单选题2 分)

给定一个初始为空的整数栈 SS 和一个空的队列 PP。我们按顺序处理输入的整数队列 A:7,5,8,3,1,4,2A: 7, 5, 8, 3, 1, 4, 2。对于队列 AA 中的每一个数,执行以下规则:如果该数是奇数,则将其压入栈 SS;如果该数是偶数,且栈 SS 非空,则弹出一个栈顶元素,并加入到队列 PP 的末尾;如果该数是偶数,且栈 SS 为空,则不进行任何操作。当队列 AA 中的所有数都处理完毕后,队列 PP 的内容是什么?

A.
5,1,35,1,3
B.
7,5,37,5,3
C.
3,1,53,1,5
D.
5,1,3,75,1,3,7

正确答案A

解析详情

【答案】A

【考点】栈与队列模拟

【解析】 奇数依次入栈;遇到 8、4、2 时弹出的栈顶分别是 5、1、3,因此队列 PP 为 `5,1,3`。

【易错点】栈按后进先出,不能按奇数的原输入顺序出队。

二、阅读程序(1)

#include <algorithm>
#include <cstdio>
#include <cstring>
inline int gcd(int a, int b) {
    if (b == 0) {
        return a;
    }
    return gcd(b, a % b);
}
int main() {
    int n;
    scanf("%d", &n);
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        for (int j = i + 1; j <= n; ++j) {
            for (int k = j + 1; k <= n; ++k) {
                if (gcd(i, j) == 1 && gcd(j, k) == 1 && gcd(i, k) == 1) {
                    ++ans;
                }
            }
        }
    }
    printf("%d\n", ans);
    return 0;
}

16 题(判断题1 分)

11 分)当输入为 22 时,程序并不会执行第 1616 行的判断语句。( )

正确答案正确

解析详情

【答案】正确

【考点】三重循环边界

【解析】 当 n=2n=2 时,`i=1,j=2` 后 `k` 从 3 开始,已经大于 nn,最内层循环和判断语句都不会执行。

【易错点】要检查最内层循环的初值,而不是只看外层循环能否进入。

17 题(判断题1.5 分)

将第 1616 行中的 `&& gcd(i,k)==1` 删去不会影响程序运行结果。( )

正确答案错误

解析详情

【答案】错误

【考点】两两互质条件

【解析】 删去 `gcd(i,k)==1` 后会错误计入如 (2,3,4)(2,3,4):前两对互质,但 2 与 4 不互质,因此结果会改变。

【易错点】相邻两对互质不能推出三个数两两互质。

18 题(判断题1.5 分)

(错题,请选择 B 获得分数)当输入的 n3n \geq 3 的时候,程序总是输出一个正整数。( )

正确答案正确(另接受:错误)

解析详情

【答案】正确(本题作废,错误也接受)

【考点】边界样例与作废题处理

【解析】 对任意 n3n\ge3,三元组 (1,2,3)(1,2,3) 都存在且两两互质,所以程序至少输出 1,原判断在数学上正确;洛谷题面标记本题为错题,因此系统同时接受两种作答。

【易错点】本题要区分数学结论与原卷作废后的计分规则。

19 题(单选题3 分)

将第 77 行的 `gcd(b, a%b)` 改为 `gcd(a, a%b)` 后,程序可能出现的问题是( )。

A.
输出的答案大于原答案。
B.
输出的答案小于原答案。
C.
程序有可能陷入死循环。
D.
可能发生整型溢出问题。

正确答案B

解析详情

【答案】B

【考点】递归参数变化

【解析】 改写后第二个参数仍严格减小,函数不会死循环,但最终总返回第一个参数;三个 `gcd` 判断无法同时为 1,输出降为 0。

【易错点】参数写错会导致结果错误,不代表递归一定无法终止。

20 题(单选题3 分)

当输入为 88 的时候,输出为( )。

A.
3737
B.
4242
C.
3535
D.
2525

正确答案D

解析详情

【答案】D

【考点】枚举与互质判断

【解析】 枚举 1i<j<k81\le i<j<k\le8 并检查三对最大公约数,共有 25 个合法三元组,因此输出 25。

【易错点】必须检查三对数,不能只检查相邻的两对。

21 题(单选题3 分)

调用 gcd(36,42)\gcd(36, 42) 会返回( )。

A.
66
B.
252252
C.
33
D.
22

正确答案A

解析详情

【答案】A

【考点】欧几里得算法

【解析】 42mod36=642\bmod36=636mod6=036\bmod6=0,所以 `gcd(36,42)` 返回 6。

【易错点】最大公约数不是两个数的乘积或最小公倍数。

二、阅读程序(2)

#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
int n, k;
int a[200007];
int ans[200007];
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    std::sort(a + 1, a + n + 1);
    n = std::unique(a + 1, a + n + 1) - a - 1;
    for (int i = 1, j = 0; i <= n; ++i) {
        for (; j < i && a[i] - a[j + 1] > k; ++j) 
            ;
        ans[i] = ans[j] + 1;
    }
    printf("%d\n", ans[n]);
    return 0;
}

22 题(判断题1.5 分)

当输入为 `3 1 3 2 1` 时,输出结果为 22。( )

正确答案正确

解析详情

【答案】正确

【考点】排序去重与双指针 DP

【解析】 输入排序去重后为 `1,2,3`;递推得到 `ans[1]=1`、`ans[2]=1`、`ans[3]=2`,最终输出 2。

【易错点】输入中的 k=1k=1,不能把它当作数组元素。

23 题(判断题1.5 分)

假设输入的 nn 为正整数,输出的答案一定小于等于 nn,大于等于 11。( )

正确答案正确

解析详情

【答案】正确

【考点】递推值范围

【解析】 `ans[i]=ans[j]+1` 且 0j<i0\le j<i,从 `ans[0]=0` 出发可得最终答案至少为 1、至多为去重后的 nn

【易错点】程序中的 nn 在去重后可能变小,但范围结论仍成立。

24 题(判断题1.5 分)

将第 14 行的 `n = std::unique(a + 1, a + n + 1) - a - 1;` 删去后,有可能出现与原本代码不同的输出结果。( )

正确答案错误

解析详情

【答案】错误

【考点】去重对分组结果的影响

【解析】 数组已经排序,重复值只会落在同一段内部;保留这些重复值不会改变由差值 kk 决定的分段次数,因此输出不变。

【易错点】删除去重会增加元素个数,但不一定增加该递推计算的组数。

25 题(单选题3 分)

假设输入的 aa 数组和 kk 均为正整数,执行第 18 行代码时,一定满足的条件不包括( )。

A.
j<ij < i
B.
a[i]a[j]>ka[i] - a[j] > k
C.
j<nj < n
D.
a[j]<a[i]a[j] < a[i]

正确答案B

解析详情

【答案】B

【考点】双指针循环不变量

【解析】 循环退出只保证下一候选 `a[j+1]` 与 `a[i]` 的差不超过 kk;当 j=0j=0 时,`a[i]-a[j]>k` 未必成立,所以 B 不是必然条件。

【易错点】应根据循环退出条件推导,不能把 `j` 和 `j+1` 混为一谈。

26 题(单选题3 分)

当输入的 n=100n=100k=2k=2a={1,2,,100}a = \{1, 2, \dots, 100\} 时,输出为( )。

A.
3434
B.
100100
C.
5050
D.
3333

正确答案A

解析详情

【答案】A

【考点】滑动窗口分组

【解析】 k=2k=2 时每组最多覆盖 3 个连续整数,递推相当于每 3 个数增加一组,故答案为 100/3=34\lceil100/3\rceil=34

【易错点】最后不足 3 个数仍需单独计为一组。

27 题(单选题3 分)

假设输入的 aa 数组和 kk 均为正整数,但 aa 数组不一定有序,则若误删去第 13 行的 `std::sort(a + 1, a + n + 1);`,程序有可能出现的问题有( )。

A.
输出的答案比原本答案更大
B.
输出的答案比原本答案更小
C.
出现死循环行为
D.
以上均可能发生

正确答案B

解析详情

【答案】B

【考点】排序前提与双指针

【解析】 去掉排序后,`j` 单调前移所依赖的有序性被破坏;例如适当的乱序输入会漏计分组,使输出小于原程序。

【易错点】双指针算法通常依赖单调性,不能只删除排序而保留原递推。

二、阅读程序(3)

#include <algorithm>
#include <cstdio>
#include <cstring>
#define ll long long
int f[5007][5007];
int a[5007], b[5007];
int n;
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &b[i]);
    }
    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= n; ++j) {
            f[i][j] = std::max(f[i][j], std::max(f[i - 1][j], f[i][j - 1]));
            if (a[i] == b[j]) {
                f[i][j] = std::max(f[i][j], f[i - 1][j - 1] + 1);
            }
        }
    }
    printf("%d\n", f[n][n]);
    return 0;
}

28 题(判断题1.5 分)

当输入 `4 1 2 3 4 1 3 2 2` 时,输出为 2。( )

正确答案正确

解析详情

【答案】正确

【考点】最长公共子序列

【解析】 两个序列分别为 `[1,2,3,4]` 和 `[1,3,2,2]`,最长公共子序列可取 `[1,2]` 或 `[1,3]`,长度为 2。

【易错点】公共子序列不要求元素在原序列中连续。

29 题(判断题1.5 分)

当程序运行完毕后,对于所有的 1i,jn1 \leq i, j \leq n,都一定有 f[i][j]f[n][n]f[i][j] \leq f[n][n]。( )

正确答案正确

解析详情

【答案】正确

【考点】LCS 动态规划单调性

【解析】 `f[i][j]` 是两个前缀的 LCS 长度;扩大任一前缀不会让最优值下降,因此所有状态都不超过 `f[n][n]`。

【易错点】这里比较的是前缀包含关系,不是数组下标的数值大小。

30 题(判断题1.5 分)

将第 18 行的 `f[i][j] = std::max(f[i][j], std::max(f[i-1][j], f[i][j-1]));` 删去后,并不影响程序运行结果。( )

正确答案错误

解析详情

【答案】错误

【考点】LCS 状态转移

【解析】 删除从 `f[i-1][j]` 和 `f[i][j-1]` 的转移后,程序无法表示跳过某个不匹配元素,会改变一般情况下的 LCS 结果。

【易错点】LCS 不只在当前两个元素相等时才需要保留历史最优值。

31 题(单选题3 分)

输出的答案满足的性质有( )。

A.
小于等于 nn
B.
大于等于 00
C.
不一定大于等于 11
D.
以上均是

正确答案D

解析详情

【答案】D

【考点】LCS 长度范围

【解析】 LCS 长度一定在 00nn 之间;两个序列可能没有公共元素,所以它不一定至少为 1,A、B、C 均成立。

【易错点】“输入长度为正”不能保证两个序列存在公共元素。

32 题(单选题3 分)

如果在 16 行的循环前加上以下两行:

std::sort(a+1, a+n+1);  
std::sort(b+1, b+n+1);

则答案会( )。

A.
变大或不变
B.
变小或不变
C.
一定变大
D.
不变

正确答案A

解析详情

【答案】A

【考点】排序与 LCS

【解析】 分别排序后,相同元素按相同顺序排列,LCS 可达到两个多重集合的交集大小;原 LCS 不会超过该值,所以答案只会变大或不变。

【易错点】排序可能改变相对次序,但这里改变是为了达到可匹配数量的上界。

33 题(单选题3 分)

(本题在原卷中被删除)如果输入的 a={1,2,,n}a = \{1, 2, \dots, n\},而且 bb 数组中数字均为 1n1 \sim n 中的正整数,则上述代码等价于下面哪个问题:( )。

A.
bb 数组去重后的长度
B.
bb 数组的最长上升子序列
C.
bb 数组的长度
D.
bb 数组的最大值

正确答案B

解析详情

【答案】B

【考点】LCS 与最长上升子序列

【解析】 当 a=[1,2,,n]a=[1,2,\ldots,n] 时,任何与 aa 公共的子序列都严格递增,因此求 aabb 的 LCS 等价于求 bb 的最长上升子序列。

【易错点】重复值不能在严格递增子序列中重复选取。

三、完善程序(1)字符串解码

(1)(字符串解码)“行程长度编码”(Run-Length Encoding)是一种无损压缩算法,常用于压缩重复字符较多的数据,以减少存储空间。假设原始字符串不包含数字字符。压缩规则如下:i) 如果原始字符串中一个字符连续出现 NN 次(N2N \geq 2),在压缩字符串中它被表示为“字符 + 数字 NN”。例如,编码 `A12` 代表 1212 个连续的字符 A。ii) 如果原始字符串中一个字符只出现 11 次,在压缩字符串中它就表示为该字符本身。例如,编码 `B` 代表 11 个字符 B。

以下程序实现读取压缩字符串并输出其原始的、解压后的形式。试补全程序。

#include <cctype>
#include <iostream>
#include <string>
using namespace std;

int main() {
    string z;
    cin >> z;
    string s = "";

    for (int i = 0; i < z.length(); ) {
        char ch = z[i];

        if (____ && isdigit(z[i + 1])) {
            i++;
            int count = 0;
            while (i < z.length() && isdigit(z[i])) {
                count = ____;
                i++;
            }
            for (int j = 0; j < ____; ++j) {
                s += ch;
            }
        } else {
            s += ____;
            ____;
        }
    }

    cout << s << endl;
    return 0;
}

34 题(单选题3 分)

①处应填( )

A.
i < z.length()
B.
i - 1 >= 0
C.
i + 1 < z.length()
D.
isdigit(z[i])

正确答案C

解析详情

【答案】C

【考点】字符串下标边界

【解析】 条件随后访问 `z[i+1]`,所以必须先保证 `i+1 < z.length()`,避免越界。

【易错点】当前 `i` 合法并不能保证 `i+1` 也合法。

35 题(单选题3 分)

②处应填( )

A.
count + (z[i] - '0')
B.
count * 10 + (z[i] - '0')
C.
z[i] - '0'
D.
count + 1

正确答案B

解析详情

【答案】B

【考点】十进制数字串解析

【解析】 逐位读取数字时应使用 `count = count * 10 + (z[i]-'0')`,才能正确处理 `12` 这类多位次数。

【易错点】只做加法或直接赋值会丢失之前读入的高位。

36 题(单选题3 分)

③处应填( )

A.
count - 1
B.
count
C.
10
D.
z[i] - '0'

正确答案B

解析详情

【答案】B

【考点】行程长度解码

【解析】 `count` 已保存字符连续出现的次数,因此循环边界应为 `j < count`。

【易错点】编码中的次数是总出现次数,不需要再减 1。

37 题(单选题3 分)

④处应填( )

A.
z[i+1]
B.
ch
C.
z.back()
D.
(char)z[i] + 1

正确答案B

解析详情

【答案】B

【考点】字符追加

【解析】 未跟数字时当前字符只出现一次,应把保存的当前字符 `ch` 追加到结果字符串。

【易错点】`z[i+1]` 可能不存在,也不是当前要输出的字符。

38 题(单选题3 分)

⑤处应填( )

A.
i--
B.
i = i + 2
C.
i++
D.
// 不执行任何操作

正确答案C

解析详情

【答案】C

【考点】循环下标推进

【解析】 单字符处理完成后必须执行 `i++`,让下一轮读取下一个编码字符。

【易错点】不推进 `i` 会反复处理同一字符并导致死循环。

三、完善程序(2)精明与糊涂

(2)(精明与糊涂)有 NN 个人,分为两类: i) 精明人:永远能正确判断其他人是精明还是糊涂; ii)糊涂人:判断不可靠,会给出随机的判断。

已知精明人严格占据多数,即如果精明人有 kk 个,则满足 k>N/2k > N/2

你只能通过函数 query(i,j)\text{query}(i, j) 让第 ii 个人判断第 jj 个人:返回 true\text{true} 表示判断结果为“精明人”;返回 false\text{false} 表示判断结果为“糊涂人”。你的目标是,通过这些互相判断,找出至少一个百分之百确定的精明人。同时,你无需关心 query(i,j)\text{query}(i, j) 的内部实现。

以下程序利用“精明人占多数”的优势。设想一个“消除”的过程,让人们互相判断并进行抵消。经过若干轮抵消后,最终留下的候选人必然属于多数派,即精明人。

例如,假设有三人 0,1,20, 1, 2。如果 0011 是糊涂人,而 11 也说 00 是糊涂人,则 0011 至少有一个是糊涂人。程序将同时淘汰 0011。由于三人里至少有两个精明人,我们确定 22 是精明人。

试补全程序。

#include <iostream>
#include <vector>
using namespace std;

int N;
bool query(int i, int j);

int main() {
    cin >> N;

    int candidate = 0;
    int count = ____;
    for (int i = 1; i < N; ++i) {
        if (____) {
            candidate = i;
            count = 1;
        } else {
            if (____) {
                ____;
            } else {
            count++;
            }
        }
    }
    cout << ____ << endl;
    return 0;
}

39 题(单选题3 分)

①处应填( )

A.
0
B.
1
C.
N
D.
-1

正确答案B

解析详情

【答案】B

【考点】多数投票初始化

【解析】 初始候选人 0 自己提供 1 票,因此 `count` 应初始化为 1;更换候选人时也同样重置为 1。

【易错点】`count` 表示当前候选人的净支持计数,不是总人数。

40 题(单选题3 分)

②处应填( )

A.
count < 0
B.
count == 1
C.
count == 0
D.
query(candidate, i) == false

正确答案C

解析详情

【答案】C

【考点】候选人重置条件

【解析】 当抵消后 `count == 0` 时,旧候选人已无净优势,应把当前的 `i` 设为新候选人并把计数重置为 1。

【易错点】候选人被某一次查询质疑时不应立即无条件替换。

41 题(单选题3 分)

③处应填( )

A.
query(candidate, i) == false
B.
query(i, candidate) == true
C.
query(candidate, i) == false && query(i, candidate) == false
D.
query(candidate, i) == false || query(i, candidate) == false

正确答案D

解析详情

【答案】D

【考点】成对消除条件

【解析】 只要两人中任意一方判断另一方为糊涂人,两人中就至少有一名糊涂人,可以执行一次抵消;对应两个判断结果以 `||` 连接。

【易错点】要求两个判断都为 false 会漏掉同样可以安全抵消的情况。

42 题(单选题3 分)

④处应填( )

A.
count--
B.
break
C.
count++
D.
candidate = i

正确答案A

解析详情

【答案】A

【考点】多数投票抵消

【解析】 触发消除条件时,当前人与候选人的一票相互抵消,因此应执行 `count--`。

【易错点】抵消时不应增加计数,也不需要中止整个循环。

43 题(单选题3 分)

⑤处应填( )

A.
N - 1
B.
count
C.
candidate
D.
0

正确答案C

解析详情

【答案】C

【考点】多数候选人输出

【解析】 循环结束后 `candidate` 保存抵消过程留下的多数派候选人,程序应输出该变量。

【易错点】`count` 只是净票数,不能用来代替候选人的编号。