CSP-J 2025 第一轮 · 客观题精讲讲义

试卷:CSP 2025 入门级(Junior)第一轮 · 单项选择 + 阅读程序 + 完善程序

用法:每题先独立作答,再点「显示解析」核对分步推理;右上角可切换 浅色/深色 配色。

单选题 15 阅读程序 3 段(判断+单选) 完善程序 2 段 答案均经代码验证

🗺️ 本卷知识地图

CSP-J 初赛覆盖面广。本卷可归为 8 大板块,复习时按板块查漏补缺。

① 数据表示与进制

Q1 无符号范围 232Q13 十进制/八进制/十六进制互转。记牢 210≈103

② 位运算

Q2 x&(x-1) 清除最低位的 1。

③ 递归与递推

Q3 递归求值、Q8 斐波那契取模的周期性。

④ 数据结构

Q4 哈夫曼树、Q5 图入度/出度、Q14 完全二叉树、Q15 栈与队列。

⑤ 组合计数

Q6 组合数+补集、Q11 网格路径 = 组合数。

⑥ 逻辑与语言特性

Q7 布尔表达式等价、Q9 string、Q10 引用 vs 值传递。

⑦ 排序

Q12 冒泡交换次数 = 逆序对数。

⑧ 算法阅读/完善 ⭐

欧几里得+两两互质、双指针贪心分组、LCS 动态规划、行程长度编码、摩尔投票。

第一部分 · 单项选择题(1–15)
第 1 题单选进制 / 数据范围

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

第 2 题单选位运算

执行 int x = 255; cout << (x & (x - 1)); 后输出是?

第 3 题单选递归

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);
}
第 4 题单选哈夫曼树

用 5 个权值 10, 12, 15, 20, 25 构造哈夫曼树,带权路径长度 WPL 是多少?

第 5 题单选图:度

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

第 6 题单选组合计数

从 5 名男生、4 名女生中选 4 人,要求男女都有,有多少种选法?

第 7 题单选布尔表达式等价

设 a,b,c 为布尔变量,(a && b) || (!c && a) 与下列哪个表达式 始终相等?

第 8 题单选取模数列周期

f[0]=1, f[1]=1,n≥2 时 f[n]=(f[n−1]+f[n−2]) % 7。则 f[2025] = ?

第 9 题单选C++ string

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

第 10 题单选引用 vs 值传递

调用 solve 后,x 和 y 的值分别是?

void solve(int &a, int b) {   // a 是引用, b 是副本
    a = a + b;
    b = a - b;
    a = a - b;
}
int main() {
    int x = 5, y = 10;
    solve(x, y);
}
第 11 题单选网格路径=组合数

机器人从 (1,1) 出发,每次只能向右或向下走一格,到达 (4,5) 有多少种路径?

第 12 题单选冒泡=逆序对

用冒泡排序对 {6, 1, 5, 2, 4} 升序排序,需进行多少次元素交换?

第 13 题单选进制转换

十进制 72010 与八进制 2708 的和,用十六进制表示是多少?

第 14 题单选完全二叉树

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

第 15 题单选栈与队列模拟

空栈 S、空队列 P。按序处理 A: 7,5,8,3,1,4,2。奇数压入 S;偶数且 S 非空则弹出栈顶加入 P 末尾;偶数且 S 空则不操作。最终 P 是什么?

第二部分 · 阅读程序(判断题 + 单选题)

📄 阅读程序(一)· 统计两两互质的三元组个数

说明:判断题正确填 A、错误填 B。下面三段共享这份程序。

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);
}
第 16 题判断

当输入为 2 时,程序并不会执行那条 if 判断语句。

第 17 题判断

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

第 18 题判断

当输入 n ≥ 3 时,程序总是输出一个正整数。(原卷标注为错题,请选 B 得分)

第 19 题单选

将递归 gcd(b, a % b) 改成 gcd(a, a % b) 后,程序可能出现的问题是?

第 20 题单选

当输入为 8 时,输出为?

第 21 题单选

调用 gcd(36, 42)(原正确版本)返回?

📄 阅读程序(二)· 排序去重 + 双指针贪心分组

排序去重后,求把这些数分成若干组、每组「最大−最小 ≤ k」所需的最少组数。

scanf("%d%d", &n, &k);
for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
std::sort(a + 1, a + n + 1);                       // 第13行
n = std::unique(a + 1, a + n + 1) - a - 1;         // 第14行:去重,n 变为去重后长度
for (int i = 1, j = 0; i <= n; ++i) {
    for (; j < i && a[i] - a[j + 1] > k; ++j) ;     // 双指针推进 j
    ans[i] = ans[j] + 1;                           // 第18行
}
printf("%d\n", ans[n]);
第 22 题判断

当输入为 3 1 / 3 2 1(n=3, k=1, 数组 3 2 1)时,输出结果为 2。

第 23 题判断

设输入的 n 为正整数,则输出的答案一定 ≤ n 且 ≥ 1。

第 24 题判断

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

第 25 题单选

设 a 数组与 k 均为正整数,执行第 18 行 ans[i]=ans[j]+1 时,一定满足的条件不包括

第 26 题单选

当 n=100, k=2, a = {1,2,…,100} 时,输出为?

第 27 题单选

设 a、k 均为正整数但 a 不一定有序。若误删第 13 行 std::sort(...),程序可能出现的问题是?

📄 阅读程序(三)· 最长公共子序列(LCS)

经典二维 DP:f[i][j] = a 前 i 个与 b 前 j 个的最长公共子序列长度,输出 f[n][n]。

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]));  // 第18行
        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]);
第 28 题判断

当输入 4 / 1 2 3 4 / 1 3 2 2 时,输出为 2。

第 29 题判断

程序运行完毕后,对所有 1 ≤ i,j ≤ n,都一定有 f[i][j] ≤ f[n][n]。

第 30 题判断

将第 18 行(从上方/左方继承 max 的那行)删去,不影响程序运行结果。

第 31 题单选

输出的答案满足的性质有?

第 32 题单选

若在循环前对 a、b 都加上 std::sort(各自升序),则答案会?

第 33 题单选原卷已删除

若输入 a = {1,2,…,n},b 中数字均为 1~n 的正整数,则该程序等价于?

第三部分 · 完善程序(单选)

🧩 完善程序(一)· 行程长度编码 RLE 解码

规则:字符连续出现 N≥2 次写成「字符+数字 N」(如 A12 = 12 个 A);只出现 1 次就写字符本身(如 B)。原串不含数字。补全 ①~⑤。

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;
完善

① 处应填?

完善

② 处应填(逐位拼出多位数字 count)?

完善

③ 处应填(重复输出 ch 的次数)?

完善

④ 处应填(单字符分支,输出当前字符)?

完善

⑤ 处应填(else 分支推进下标)?

🧩 完善程序(二)· 找出一个百分百确定的精明人(摩尔投票)

精明人严格过半(k > N/2)。query(i,j) 返回 i 对 j 的判断(true=精明)。用「互相抵消」找出多数派代表。补全 ①~⑤。

int candidate = 0;
int count = __①__;
for (int i = 1; i < N; ++i) {
    if (__②__) {              // 票数归零,换人
        candidate = i;
        count = 1;
    } else {
        if (__③__) {          // 与候选人「冲突」→ 抵消
            __④__;
        } else {
            count++;                // 一致 → 票数 +1
        }
    }
}
cout << __⑤__ << endl;
完善

① count 的初值应填?

完善

② 「换候选人」的触发条件应填?

完善

③ 「与候选人冲突(应抵消)」的条件应填?

完善

④ 冲突时应执行?

完善

⑤ 最终输出应填?