2025CSPJ初赛

· · 生活·游记

原题和主要内容来源,感谢! 修改了部分答案,主要是阅读题和最后摩尔投票部分,如有异议辛苦指出。全卷只有摩尔投票上课没讲过。做了琪露诺的有福了,j超纲考了滑动窗口。

【算法讲解116【扩展】摩尔投票大加强,线段树里捉海王-哔哩哔哩】 https://b23.tv/IL8dH0F

【【漫士】这是你学明白组合数学最好的机会-哔哩哔哩】 https://b23.tv/T74ik41

选择

题号 答案 解析要点
1 A int最大约2E9,速算32位无符号整数unsinged int最大约4E9, 2³² - 1 ≈ 4×10⁹
2 B 255(二进制 11111111)与 254(11111110)按位与结果为 254
3 B 递归计算得 calc(5) = cal(4)+cal(3)=cal(2)+1 + cal(2)+cal(1) = cal(1)+1 +1 + cal(1)+1 + 1 = 6
4 B 哈夫曼树构造后,带权路径长度为:10×3 + 12×3 + 15×2 + 20×2 + 25×2 = 186 =10*3+12*3+15*2+20*2+25*2
5 B 有向图中每条边贡献1个入度和1个出度,故入度和 = 出度和 = 边数
6 C 正难则反,排除法排除全女全男 C(9,4) - C(5,4) - C(4,4) = 126 - 5 - 1 = 120
7 C 逻辑运算符按结合律化简为 a && (b !c),选项C为 a && (!b c),不相等
8 D 打表发现斐波那契数列模7周期为16(1, 1, 2, 3, 5, 1, 6, 0, 6, 6, 5, 4, 2, 6, 1, 0),2025 mod 16 = 9,对应值为6
9 B string类支持+连接string与char;A(长度可改,甚至有resize函数)、C(length=size)、D(结尾符不计入)均错
10 C 引用传递a(x被修改为10),值传递b(y保持10)
11 B ⭐经典杨辉三角。需向右3步、向下4步,总路径数 C(7,3) = 35
12 B 冒泡排序共发生6次元素交换(第一轮4次,第二轮2次)6 1 5 2 4-> 1 5 2 4 6-> 1 2 4 5 6
13 A 十进制720 + 八进制270(十进制184)= 904,转十六进制为 0x388
14 C 数学归纳法可证(也可以想奇数时多一个叶子,偶数是正好叶子持平)n个节点的完全二叉树,叶子节点数为 n - n//2
15 A 模拟,队列P依次存入 5、1、3

T16 两两互质的三元组+辗转相除法求GCD

import math

def gcd(a, b):
    return math.gcd(a, b)

n = 8
ans = 0

for i in range(1, n + 1):
    for j in range(i + 1, n + 1):
        for k in range(j + 1, n + 1):
            if gcd(i, j) == 1 and gcd(j, k) == 1 and gcd(i, k) == 1:
                ans += 1
                print(i,j,k)

print(ans)
题号 答案 解析要点
16 输入 n=2 时,i\<j\<k 无合法组合,第16行判断不执行
17 × 删去 gcd(i,k)==1 会漏选 i 与 k 不互质的情况,结果偏大
18 n≥3 时,至少存在 (1,2,3) 等两两互质三元组,输出为正整数
19 B 举例试一下即可,gcd总是a不变b快速变零导致gcd结果很难是1,最后ans=0
20 D 枚举吧,试了下分类讨论也挺累的,老实模拟枚举
21 A 36 与 42 的最大公约数为 6

⭐T17把已排序、去重后的数组切成最少连续子段,使得每一段内部最大值减最小值 ≤ k,最终输出最少段数。(一般看到本题直接二分答案来着,学一下滑动窗口+DP)

#include <algorithm>
#include <cstdio>
#include <cstring>

using namespace std;

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]);

    /* 去重:unique 返回去重后尾端指针,减 a 得新长度 */
    sort(a + 1, a + n + 1);
    n = unique(a + 1, a + n + 1) - a - 1;

    /* 滑动窗口核心逻辑 */
    for (int i = 1, j = 0; i <= n; ++i) {
        while (j < i && a[i] - a[j + 1] > k) ++j;   // 把过期的左端点右移
        ans[i] = ans[j] + 1;                        // 以 a[i] 结尾的最少段数
    }

    printf("%d\n", ans[n]);
    return 0;
}
题号 题型 答案 解析要点
22 判断题 输入处理后排序去重,ans[3] = 2,输出正确
23 判断题 ans[n] 为子序列个数,范围 1 ≤ ans[n] ≤ n
24 判断题 × 重复元素差值为0,对结果没影响吧。而且本题代码对k<0的输出恒为1
25 单选题 B 退出循环时 a[i] - a[j+1] ≤ k,但 a[i] - a[j] 可能 ≤k(非必然 >k)
26 单选题 A 每3个元素为一组,100个元素对应34组,ans[100] = 34
27 单选题 A 未排序时数组无序,可能导致 ans[n] 偏大(如逆序数组,ai-aj+1<0,j指针几乎不移动,几乎没累加)

T18 LCS纯模板,典中典

题号 题型 答案 解析要点
28 判断题 a=[1,2,3,4]、b=[1,3,2,2] 的 LCS 长度为 2
29 判断题 f[i][j] 为局部 LCS 长度,必然 ≤ 全局最大值 f[n][n]
30 判断题 × 删去第18行后,无法继承 f[i-1][j] 或 f[i][j-1] 的最大值,结果错误
31 单选题 D LCS 长度 ≤ n(A对)、≥ 0(B对)、可能为 0(C对)
32 单选题 A 排序后 LCS 变为公共元素个数,可能变大(如乱序数组)或不变
33 单选题 B 若 a 为有序数组,LCS 等价于 b 的最长上升子序列(LIS)⭐题号填涂有问题的同学可以之后考虑申诉成绩

完善程序T19字符串解码T20摩尔投票

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

int main() {
    string z;
    cin >> z;
    string s = "";
    for (int i = 0; i < z.length(); ) {        // ① 初始化 i = 0
        char ch = z[i];
        if (isalpha(ch) && i + 1 < z.length() && isdigit(z[i + 1])) {
            i++;                               // 跳过字母
            int count = 0;                     // ② 初始值 count = 0
            while (i < z.length() && isdigit(z[i])) {
                count = count * 10 + (z[i] - '0'); // ③ 数字拼接
                i++;
            }
            for (int j = 0; j < count; j++)    // ④ 重复 count 次
                s += ch;
        } else {
            s += ch;                           // 普通字母
            i++;
        }
    }
    cout << s << endl;
    return 0;                                  // ⑤ return 0
}
题号 答案 解析要点
33 C 需判断下一个字符是否在字符串内(i+1 < z.length())
34 B 数字拼接逻辑:count = count * 10 + (z[i] - '0')
35 B 循环次数为解析出的重复次数 count
36 B 无后续数字时,直接添加当前字符 ch
37 C 处理完单个字符后,i 需自增1(i++)
38 B 初始候选者为 0,计数 count = 1
39 C 票数归零,更换候选者
40 D 意见不合,候选人票数-1
41 A 意见不合,候选人票数-1
42 C 最终留下的候选者为精明人,输出 candidate