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

试卷:CSP 2025 提高级(Senior)第一轮 · 单项选择 + 阅读程序 + 完善程序

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

单选题 15 阅读程序 3 段 完善程序 2 段 共 43 个作答点 答案均经代码验证

🗺️ 本卷知识地图

CSP-S 提高级第一轮,难度与覆盖面都高于入门级。本卷可归为 8 大板块。

① 组合数学

Q1 不相邻排列(插空法)、Q13 容斥原理。

② 字符串

Q2 KMP next 数组、Q4 Trie 前缀树结点数。

③ 数据结构

Q3 线段树查询、Q6 哈希线性探查、Q8 BST 遍历、Q12 堆。

④ 图论与树

Q5 拓扑排序、Q7 最小生成树、Q10 LCA 性质。

⑤ DP 与贪心

Q9 0-1 背包、Q14 重叠子问题、Q15 贪心调度。

⑥ 复杂度分析

Q11 主定理、Q26/32 递归与折半搜索量级。

⑦ 算法阅读 ⭐

DFS 计数排列、两枚鸡蛋(双蛋)最优策略、折半搜索 meet-in-the-middle。

⑧ 完善程序 ⭐

分层 Dijkstra(免费边)、组合编码群体测试。

第一部分 · 单项选择题(1–15)
第 1 题单选组合·插空

5 个红球、5 个蓝球(同色无区别)排成一排,要求任意两个蓝球都不相邻,有多少种排法?

第 2 题单选KMP next

模式串 P = abacaba,其 next 数组(最长公共前后缀长度)是?

第 3 题单选线段树查询

大小为 16(下标 0~15)的满线段树,查询区间 [3, 11] 时,最少需访问多少个结点(含路径上父结点与完全包含的结点)?

第 4 题单选Trie 前缀树

cat, car, cart, case, dog, do 插入空 Trie,构建完成(含根结点)共多少个结点?

第 5 题单选拓扑排序

含 n 个结点、m 条边的有向无环图(DAG),其拓扑排序结果有多少种可能?

第 6 题单选哈希·线性探查

大小 13 的哈希表,线性探查,H(key)=key mod 13。依次插入 18, 26, 35, 9, 68, 74。插入 74 后它落在哪个索引?

第 7 题单选最小生成树

8 个顶点(编号 1~8)的完全图,边权 = 两端编号差的绝对值。最小生成树总权重是多少?

第 8 题单选BST 遍历还原

二叉搜索树的后序遍历为 2, 5, 4, 8, 12, 10, 6,其前序遍历是?

第 9 题单选0-1 背包

背包容量 20,5 个物品重量 {7,5,4,3,6}、价值 {15,12,9,7,13}。最大总价值是多少?

第 10 题单选LCA 性质

以结点 1 为根的树中,LCA(12, 18) = 4。下列哪个 LCA 组合是不可能出现的?

第 11 题单选主定理

递归式 T(n) = 2T(n/2) + O(n2) 描述某分治算法,其时间复杂度是?

第 12 题单选最小堆

空最小堆依次插入 20, 12, 15, 8, 10, 5,再连续两次 delete-min,堆顶元素是?

第 13 题单选容斥原理

1 到 1000 之间,不能被 2、3、5 中任意一个整除的整数有多少个?

第 14 题单选重叠子问题

朴素递归求斐波那契是指数级、而 DP/迭代是线性,造成巨大差异的根本原因是?

第 15 题单选贪心调度

5 个不可抢占任务,处理时长 {3,4,2,5,1}、截止时刻 {5,10,3,15,11},超时惩罚=处理时长。为最小化总惩罚,应优先执行哪个?

第二部分 · 阅读程序

📄 阅读程序(一)· DFS 计数特殊排列

判断题正确填 A、错误填 B。统计 1~n 的排列 p 中,不存在「相邻位置后一个 = 前一个 +1」的排列数。

bool flag[27];
int n, p[27], ans = 0;
void dfs(int k) {
    if (k == n + 1) { ++ans; return; }          // 填满 n 个位置,计数
    for (int i = 1; i <= n; ++i) {
        if (flag[i]) continue;                   // 第14行:i 已用过
        if (k > 1 && i == p[k - 1] + 1) continue; // 不能等于上一个 +1
        p[k] = i; flag[i] = true;
        dfs(k + 1);
        flag[i] = false;                         // 第19行:回溯
    }
}
int main() { scanf("%d", &n); dfs(1); printf("%d\n", ans); }  // 第25行 dfs
第 16 题判断

当输入 n=3 时,程序输出 3。

第 17 题判断

dfs 运行过程中,k 的取值满足 1 ≤ k ≤ n+1。

第 18 题判断

删除第 19 行的 flag[i]=false;,对答案不会产生影响。

第 19 题单选

当输入 n=4 时,程序输出为?

第 20 题单选

若运行第 25 行 dfs 前数组 p 的初值并不全为 0,对程序的影响是?

第 21 题单选

删去第 14 行的 if(flag[i]) continue;,输入 3,输出是?

📄 阅读程序(二)· 两枚鸡蛋找临界楼层

k 为临界值(h≥k 会摔碎),最多 2 枚蛋(cnt_broken≤2)。guess1 线性逐层试;guess2 用「三角数」步长的最优策略。「猜测次数」= 调用 check 的次数。

int cnt_broken = 0, cnt_check = 0, n, k;
bool check(int h) {                       // 试探楼层 h
    ++cnt_check;
    if (cnt_broken == 2) return false;    // 没蛋了
    if (h >= k) { ++cnt_broken; return true; }
    else return false;
}
void guess1(int n){ for(int i=1;i<=n;++i) if(check(i)){ assert_ans(i); return; } }
void guess2(int n){                       // 先求最小 w 使 w(w+1)/2 ≥ n
    int w; for(w=1; w*(w+1)/2 < n; ++w);
    for(int ti=w, nh=w; ; --ti, nh+=ti, nh=min(nh,n)){
        if(check(nh)){                    // 第一枚蛋碎,第二枚线性补查
            for(int j=nh-ti+1; j<nh; ++j) if(check(j)){ assert_ans(j); return; }
            assert_ans(nh); return;
        }
    }
}  // 主函数:t=1 调 guess1,否则 guess2
第 22 题判断

输入 "6 5 1" 时猜测次数为 5;输入 "6 5 2" 时猜测次数为 3。

第 23 题判断

不管 n、k 为多少,t=2 的猜测数总是 ≤ t=1 的猜测数。

第 24 题判断

不管 t=1 或 t=2,程序都一定能猜到正确结果。

第 25 题单选

函数 guess1 运行过程中,cnt_broken 的值最多为?

第 26 题单选

函数 guess2 运行中,最多使用的猜测次数量级为?

第 27 题单选

当 n=100 时,t=1 与 t=2 分别需要的「最多」猜测次数是?

📄 阅读程序(三)· 折半搜索(meet-in-the-middle)

统计满足 Σ kᵢ·xᵢpᵢ = 0(xᵢ ∈ [1,m])的解数。把 n 个变量分两半,各自枚举所有取值之和,再配对求和为 0 的组合数。

int mpow(int x,int k){ int a=1; for(;k;k>>=1,x=x*x) if(k&1) a=a*x; return a; } // 快速幂 xᵏ
void dfs(vector<int>& ans,int& cnt,int l,int r,int v){
    if(l>r){ ++cnt; ans.push_back(v); return; }
    for(int i=1;i<=m;++i) dfs(ans,cnt,l+1,r, v + k[l]*mpow(i,p[l]));  // 枚举 x_l = i
}
// 主:dfs 前半得 ans1、后半得 ans2;ans1 排序去重并记重数 cntans1;
std::sort(ans2.begin(), ans2.end());                  // 第51行
// 双指针:对每个 ans2 找 ans1 中使和为 0 的项,累加重数 → ans
第 28 题判断

删除第 51 行 std::sort(ans2…) 后,输出结果不会受影响。

第 29 题判断

假设不溢出,mpow(x,k) 的功能是求 xk

第 30 题判断

代码中(排序后那段循环)的目的是为了将 ans1 数组进行「去重」操作。

第 31 题单选

当输入为 3 15 / 1 2 / -1 2 / 1 2 时,输出结果为?(即求 x₁²−x₂²+x₃²=0、x∈[1,15] 的解数)

第 32 题单选

记 p 数组元素最大值为 P,则代码的时间复杂度是?

第 33 题单选

本题所求出的是?

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

🧩 完善程序(一)· 带一条「免费边」的最短路

无向图非负边权,整条路径中至多选一条边首次经过时费用记 0。用分层 Dijkstra:状态 (结点 u, 是否已用免费 0/1),d[u][0/1]。补全 ①~⑤。

d[s][0] = 0;
pq.push({0, s, __①__});                    // 起点,免费机会未用
while (!pq.empty()) {
    auto [dist, u, used] = pq.top(); pq.pop();
    if (dist > __②__) continue;            // 过期状态跳过
    for (auto &e : adj[u]) {
        int v = e.to, w = e.weight;
        if (d[u][used] + w < __③__) {        // 正常走这条边
            __③__ = d[u][used] + w;
            pq.push({__③__, v, used});
        }
        if (used == 0) {                       // 把这条边当免费边
            if (__④__ < d[v][1]) {
                d[v][1] = d[u][used];
                pq.push({d[v][1], v, 1});
            }
        }
    }
}
cout << __⑤__ << endl;
第 34 题完善 ①

① 处应填?

第 35 题完善 ②

② 处应填(过期状态判断)?

第 36 题完善 ③

③ 处应填(正常走边、保持 used 不变的松弛目标)?

第 37 题完善 ④

④ 处应填(用免费边到 v 的新代价)?

第 38 题完善 ⑤

⑤ 处应填(最终答案)?

🧩 完善程序(二)· 组合编码的群体测试

n 条生产线恰有 1 条有缺陷,每轮把若干产品混批发货,含缺陷则退货(1)否则收货(0),退货总数 ≤ k。求最少轮数 w 并给每条线分配一个「≤k 个 1」的不同码字以唯一定位。补全 ①~⑤。

// count_patterns(w,k): 长度 w、1 的个数 ≤ k 的码字总数
int solve(int n, int k){
    int w = 1;
    while (__①__) ++w;                // 取最小 w 使码字数 ≥ n
    cout << w << endl;
    vector<vector<int>> code(n, vector<int>(w, 0));
    int idx = 0;
    for (int ones = 0; ones <= k && idx < n; ++ones) {
        vector<int> bits(w, 0);
        fill(bits.begin(), bits.begin()+ones, 1);  // [1..1,0..0]
        do {
            for (int b=0;b<w;++b) code[idx][b]=bits[b];
            if (++idx >= n) break;
        } while (__②__);              // 枚举该 ones 下所有排列
    }
    vector<vector<int>> plan(w);
    for (int i=0;i<w;++i) for (int j=0;j<n;++j)
        if (__③__) plan[i].push_back(j);   // 第 i 批含第 j 条线?
    int signature = test_subset(plan);
    vector<int> sig_bits(w, 0);
    for (int i=0;i<w;++i) if (__④__) sig_bits[i]=1; // 取出第 i 位
    for (int j=0;j<n;++j) if (__⑤__) return j;   // 码字匹配的即缺陷线
}
第 39 题完善 ①

① 处应填(while 继续条件)?

第 40 题完善 ②

② 处应填(枚举固定 1-个数的所有排列)?

第 41 题完善 ③

③ 处应填(第 i 批是否包含第 j 条线)?

第 42 题完善 ④

④ 处应填(取出 signature 的第 i 位)?

第 43 题完善 ⑤

⑤ 处应填(找码字与测试结果一致的生产线)?