#FR1005. CSP 2026 提高级第一轮 模拟卷(一)

CSP 2026 提高级第一轮 模拟卷(一)

第 1 题(2 分)

一个有 1010 个顶点的无向简单图(无自环、无重边),要保证该图一定连通,至少需要多少条边?

{{ select(1) }}

  • 3737
  • 99
  • 1010
  • 4545

第 2 题(2 分)

一个无向带权图有 66 个顶点、99 条边,边及其权值为:(1,2,4)(1,2,4)(1,3,1)(1,3,1)(2,3,2)(2,3,2)(2,4,5)(2,4,5)(3,4,8)(3,4,8)(3,5,10)(3,5,10)(4,5,2)(4,5,2)(4,6,6)(4,6,6)(5,6,3)(5,6,3)。该图最小生成树的边权之和是?

{{ select(2) }}

  • 1313
  • 1212
  • 1414
  • 1515

第 3 题(2 分)

散列表长度为 1111,散列函数 h(x)=xmod11h(x)=x \bmod 11,使用线性探查法处理冲突。依次插入 47,7,29,11,16,92,22,847, 7, 29, 11, 16, 92, 22, 8,则关键字 88 最终存放在哪个地址(地址从 00 编号)?

{{ select(3) }}

  • 88
  • 1010
  • 00
  • 99

第 4 题(2 分)

用数组表示的小根堆(下标从 00 开始,元素依次为 1,3,2,7,4,5,6,9,81, 3, 2, 7, 4, 5, 6, 9, 8)。执行一次「删除最小元素」操作(把末尾元素移到根后下沉)之后,数组的内容是?

{{ select(4) }}

  • 2,3,5,7,4,6,8,92, 3, 5, 7, 4, 6, 8, 9
  • 2,3,5,7,4,8,6,92, 3, 5, 7, 4, 8, 6, 9
  • 8,3,2,7,4,5,6,98, 3, 2, 7, 4, 5, 6, 9
  • 2,4,5,7,8,6,9,32, 4, 5, 7, 8, 6, 9, 3

第 5 题(2 分)

对区间 [1,13][1, 13] 递归建一棵线段树(每个结点表示区间 [l,r][l,r],当 l<rl<r 时以 mid=(l+r)/2mid=\lfloor (l+r)/2 \rfloor 分成 [l,mid][l,mid][mid+1,r][mid+1,r] 两个子结点),则这棵树共有多少个结点?

{{ select(5) }}

  • 2626
  • 2727
  • 1313
  • 2525

第 6 题(2 分)

字符串 ababaab 的 KMP 失配数组 nextnextnext[i]next[i] 表示前 ii 个字符组成的前缀中,真前缀与真后缀相等的最大长度,下标从 11 开始)是?

{{ select(6) }}

  • 0,0,1,2,3,0,10, 0, 1, 2, 3, 0, 1
  • 0,1,0,1,2,2,30, 1, 0, 1, 2, 2, 3
  • 0,0,1,2,3,1,20, 0, 1, 2, 3, 1, 2
  • 0,0,1,2,3,4,20, 0, 1, 2, 3, 4, 2

第 7 题(2 分)

120261 \sim 2026 的所有正整数中,既不能被 33 整除、也不能被 55 整除、也不能被 77 整除的数共有多少个?

{{ select(7) }}

  • 926926
  • 11571157
  • 927927
  • 11001100

第 8 题(2 分)

1,2,,121, 2, \dots, 121212 个数中选出 44 个,要求任意两个所选的数都不相邻(即不存在两个所选数之差为 11)。共有多少种不同的选法?

{{ select(8) }}

  • 210210
  • 126126
  • 495495
  • 7070

第 9 题(2 分)

以下 C++ 代码段中,语句 s++; 的执行次数关于 nn 的量级是?

int s = 0;
for (int i = 1; i <= n; i++)
    for (int j = i; j <= n; j += i)
        s++;

{{ select(9) }}

  • Θ(n)\Theta(n)
  • Θ(nlogn)\Theta(n \log n)
  • Θ(n2)\Theta(n^2)
  • Θ(nn)\Theta(n \sqrt n)

第 10 题(2 分)

一棵二叉树中,度为 00 的结点(叶子)有 2525 个,则度为 22 的结点有多少个?

{{ select(10) }}

  • 2525
  • 2626
  • 2424
  • 无法确定

第 11 题(2 分)

88 个元素,初始时每个元素各成一个集合。并查集采用按秩合并(秩为树高,合并时把矮树挂到高树下;等高时把第二棵挂到第一棵下并使第一棵的秩加一),且过程中不做任何查询、因而不发生路径压缩。依次执行 union(1,2)union(1,2)union(3,4)union(3,4)union(5,6)union(5,6)union(7,8)union(7,8)union(1,3)union(1,3)union(5,7)union(5,7)union(1,5)union(1,5) 后,所得这棵树的高度(以边数计)是?

{{ select(11) }}

  • 22
  • 44
  • 77
  • 33

第 12 题(2 分)

连续掷两次均匀的六面骰子,两次点数之和为 88 的概率是?

{{ select(12) }}

  • 16\dfrac{1}{6}
  • 19\dfrac{1}{9}
  • 536\dfrac{5}{36}
  • 112\dfrac{1}{12}

第 13 题(2 分)

44 件物品,(重量, 价值) 依次为 (5,10)(5,10)(4,40)(4,40)(6,30)(6,30)(3,50)(3,50),背包容量为 1010,每件物品至多取一次。能获得的最大总价值是?

{{ select(13) }}

  • 9090
  • 8080
  • 100100
  • 120120

第 14 题(2 分)

欧拉函数 φ(n)\varphi(n) 表示 1n1 \sim n 中与 nn 互质的正整数个数。已知 2026=2×10132026 = 2 \times 101310131013 是质数,则 φ(2026)\varphi(2026) 的值是?

{{ select(14) }}

  • 10131013
  • 10121012
  • 20252025
  • 506506

第 15 题(2 分)

十进制数 20262026 用十六进制表示是?

{{ select(15) }}

  • 7AE16\text{7AE}_{16}
  • 375216\text{3752}_{16}
  • 7EA16\text{7EA}_{16}
  • 7E216\text{7E2}_{16}

第 16 题(13 分)

阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填 A,错误填 B;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分。题中"第 NN 行"指代码块中从第一行 #include 起算的第 NN 行)

#include <cstdio>
typedef unsigned int uint;
int n;
uint a[100007];
uint f(uint x) {
    uint c = 0;
    while (x) { x &= x - 1; ++c; }
    return c;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%u", &a[i]);
    uint best = 0;
    int cnt = 0;
    for (int i = 1; i <= n; ++i)
        for (int j = i + 1; j <= n; ++j) {
            uint v = a[i] ^ a[j];
            if (f(v) > f(best)) { best = v; cnt = 1; }
            else if (f(v) == f(best)) ++cnt;
        }
    printf("%u %d\n", f(best), cnt);
    return 0;
}

假设输入满足 2n10002 \leq n \leq 1000aia_i 为不超过 23212^{32}-1 的非负整数。

判断题

16.(11 分)函数 f(x) 返回的是 xx 的二进制表示中 11 的个数。( )

{{ select(16) }}

  • T
  • F
  1. 当输入的所有 aia_i 都相等时,程序输出的第二个数是 n(n1)2\dfrac{n(n-1)}{2}。( )

{{ select(17) }}

  • T
  • F
  1. 程序输出的第一个数一定不超过 3131。( )

{{ select(18) }}

  • T
  • F

单选题

  1. 当输入为 31 2 3 时,输出为( )。 {{ select(19) }}
  • 2 2
  • 1 2
  • 2 1
  • 2 3
  1. ww 为一个 unsigned int 的二进制位数(本题中 w=32w=32)。若把 ww 也计入,则该程序的时间复杂度为( )。 {{ select(20) }}
  • O(n2logn)O(n^2 \log n)
  • O(nw)O(n w)
  • O(n2w2)O(n^2 w^2)
  • O(n2w)O(n^2 w)
  1. 当输入为 51 2 4 8 16 时,输出为( )。 {{ select(21) }}
  • 2 1
  • 2 10
  • 1 10
  • 4 10

第 17 题(13.5 分)

#include <algorithm>
#include <cstdio>
int n;
int a[100007], f[100007], g[100007];
int solve1() {
    int ans = 0;
    for (int i = 1; i <= n; ++i) {
        f[i] = 1;
        for (int j = 1; j < i; ++j)
            if (a[j] < a[i] && f[j] + 1 > f[i]) f[i] = f[j] + 1;
        if (f[i] > ans) ans = f[i];
    }
    return ans;
}
int solve2() {
    int len = 0;
    for (int i = 1; i <= n; ++i) {
        int p = (int)(std::lower_bound(g + 1, g + len + 1, a[i]) - g);
        g[p] = a[i];
        if (p > len) len = p;
    }
    return len;
}
int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    printf("%d %d\n", solve1(), solve2());
    return 0;
}

假设输入满足 1n1051 \leq n \leq 10^5aia_i 均为 int 范围内的整数。

判断题

  1. 对任意合法输入,程序输出的两个数总是相等。( )

{{ select(22) }}

  • T
  • F
  1. 程序运行结束后,数组 g 的前 len 个位置 g[1..len] 中存放的,一定是原序列的某个最长上升子序列。( )

{{ select(23) }}

  • T
  • F
  1. 若把 solve1 中的 a[j] < a[i] 改为 a[j] <= a[i],同时把 solve2 中的 lower_bound 改为 upper_bound,则对任意输入两个函数的返回值仍然相等。( )

{{ select(24) }}

  • T
  • F

单选题

  1. solve1solve2 的时间复杂度依次为( )。 {{ select(25) }}
  • O(n2)O(n^2)O(n)O(n)
  • O(nlogn)O(n \log n)O(nlogn)O(n \log n)
  • O(n2)O(n^2)O(nlogn)O(n \log n)
  • O(n2)O(n^2)O(n2)O(n^2)
  1. 当输入为 83 1 4 1 5 9 2 6 时,输出为( )。 {{ select(26) }}
  • 5 5
  • 4 5
  • 3 3
  • 4 4
  1. solve2 中,循环进行到第 ii 轮结束时,g[k]1klen1 \leq k \leq len)的含义是( )。 {{ select(27) }}
  • ii 个数中所有长度为 kk 的上升子序列的最小结尾元素
  • ii 个数中长度为 kk 的上升子序列的个数
  • ii 个数中第 kk 小的元素
  • ii 个数中长度为 kk 的上升子序列的最大结尾元素

第 18 题(13.5 分)

#include <cstdio>
int n, k;
int a[100007], cnt[100007];
int main() {
    scanf("%d%d", &n, &k);
    for (int i = 1; i <= n; ++i) scanf("%d", &a[i]);
    int kinds = 0, ans = 0, best = 0;
    for (int l = 1, r = 0; l <= n; ++l) {
        while (r < n && (kinds < k || cnt[a[r + 1]] > 0)) {
            ++r;
            if (cnt[a[r]] == 0) ++kinds;
            ++cnt[a[r]];
        }
        if (r - l + 1 > ans) { ans = r - l + 1; best = l; }
        --cnt[a[l]];
        if (cnt[a[l]] == 0) --kinds;
    }
    printf("%d %d\n", ans, best);
    return 0;
}

假设输入满足 1n1051 \leq n \leq 10^51kn1 \leq k \leq n1ai1051 \leq a_i \leq 10^5

判断题

  1. 程序求的是「最长的、其中不同元素种数不超过 kk 的连续子数组」的长度,以及这样的子数组中最靠左的一个的起始下标。( )

{{ select(28) }}

  • T
  • F
  1. 内层 while 循环的总执行次数是 O(n)O(n) 的,因此整个程序的时间复杂度为 O(n)O(n)。( )

{{ select(29) }}

  • T
  • F
  1. knk \geq n,则程序一定输出 n 1。( )

{{ select(30) }}

  • T
  • F

单选题

  1. 当输入为 7 21 2 1 3 3 2 2 时,输出为( )。 {{ select(31) }}
  • 3 1
  • 4 4
  • 4 1
  • 5 3
  1. 变量 r 在整个程序运行过程中( )。 {{ select(32) }}
  • 单调不减,且最终一定等于 nn
  • 可能减小
  • 单调不减,但最终不一定等于 nn
  • 每轮外层循环都会重新从 ll 开始
  1. 若把第 99 行的循环条件 kinds < k || cnt[a[r + 1]] > 0 改为 kinds < k,则程序( )。 {{ select(33) }}
  • 输出不变
  • 输出的第一个数可能变小
  • 输出的第一个数可能变大
  • 会陷入死循环

第 19 题(15 分)

三、完善程序(单选题,每小题 3 分,共计 30 分)

(1)(字符串匹配)给定文本串 ss 与模式串 tt(长度分别不超过 10610^6,均只含小写字母),统计 ttss 中出现的次数(允许重叠)。例如 s=s= aaaat=t= aa 时答案为 33

程序采用 KMP 算法。先对 tt 求出失配数组 nxt,其中 nxt[i] 表示 tt 的前 ii 个字符组成的前缀里,真前缀与真后缀相等的最大长度;再用一个指针 j 表示"当前已匹配的长度"扫描 ss:字符失配时让 j 沿 nxt 回退,匹配成功时 j 加一;一旦 j 达到 mm 就计数一次,并让 j 回退到 nxt[j] 以便继续寻找重叠的下一次出现。试补全程序。

#include <cstdio>
#include <cstring>
const int N = 1000006;
char s[N], t[N];
int nxt[N];
int n, m;
int main() {
    scanf("%s%s", s + 1, t + 1);
    n = strlen(s + 1); m = strlen(t + 1);
    nxt[1] = 0;
    for (int i = 2, j = 0; i <= m; ++i) {
        while (j > 0 && t[i] != t[j + 1]) j = __①__;
        if (t[i] == t[j + 1]) ++j;
        nxt[i] = __②__;
    }
    int cnt = 0;
    for (int i = 1, j = 0; i <= n; ++i) {
        while (j > 0 && __③__) j = nxt[j];
        if (s[i] == t[j + 1]) ++j;
        if (__④__) { ++cnt; j = __⑤__; }
    }
    printf("%d\n", cnt);
    return 0;
}
  1. ①处应填( ) {{ select(34) }}
  • j - 1
  • nxt[j - 1]
  • 0
  • nxt[j]
  1. ②处应填( ) {{ select(35) }}
  • j
  • j + 1
  • i - j
  • 0
  1. ③处应填( ) {{ select(36) }}
  • s[i] == t[j + 1]
  • s[i] != t[j + 1]
  • s[i] != t[j]
  • j < m
  1. ④处应填( ) {{ select(37) }}
  • j == m
  • j >= m - 1
  • j == m - 1
  • i == n
  1. ⑤处应填( ) {{ select(38) }}
  • 0
  • j - 1
  • nxt[j]
  • nxt[j - 1]

第 20 题(15 分)

(2)(一次免费的最短路)给定一个 nn 个点 mm 条边的无向带权图(1n1051 \leq n \leq 10^50m2×1050 \leq m \leq 2\times10^5,边权为不超过 10910^9 的非负整数),起点 SS、终点 TT。你有一次机会把路径上某一条边的通行费用当作 00(也可以不使用这次机会)。求从 SS 走到 TT 的最小总费用。若 TT 不可达,输出一个极大值。

程序使用分层图(拆点)+ 堆优化 Dijkstra:把每个点拆成两个状态,d[u][0] 表示走到 uu尚未使用免费机会时的最小费用,d[u][1] 表示走到 uu已经用掉免费机会时的最小费用。层内沿普通边转移、边权照付;从第 00 层跨到第 11 层的转移表示"这条边免费",边权按 00 计。答案取两层中终点的较小值。试补全程序。

#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
using namespace std;
const int N = 100005, M = 400005;
int head[N], nxt_[M], to_[M], w_[M], ec;
int d[N][2];
bool vis[N][2];
int n, m, S, T;
void add(int u, int v, int w) { to_[++ec] = v; w_[ec] = w; nxt_[ec] = head[u]; head[u] = ec; }
struct Node {
    int dis, u, k;
    bool operator<(const Node &o) const { return dis > o.dis; }
};
int main() {
    scanf("%d%d%d%d", &n, &m, &S, &T);
    for (int i = 1; i <= m; ++i) {
        int u, v, w; scanf("%d%d%d", &u, &v, &w);
        add(u, v, w); add(v, u, w);
    }
    memset(d, 0x3f, sizeof(d));
    priority_queue<Node> q;
    __①__;
    q.push((Node){0, S, 0});
    while (!q.empty()) {
        Node cur = q.top(); q.pop();
        int u = cur.u, k = cur.k;
        if (__②__) continue;
        vis[u][k] = true;
        for (int e = head[u]; e; e = nxt_[e]) {
            int v = to_[e], w = w_[e];
            if (d[u][k] + w < d[v][k]) { d[v][k] = d[u][k] + w; q.push((Node){d[v][k], v, k}); }
            if (__③__) { d[v][1] = d[u][0]; q.push((Node){d[v][1], v, 1}); }
        }
    }
    printf("%d\n", __④__);
    return 0;
}
  1. ①处应填( ) {{ select(39) }}
  • d[S][1] = 0
  • d[S][0] = 1
  • d[T][0] = 0
  • d[S][0] = 0
  1. ②处应填( ) {{ select(40) }}
  • vis[u][1]
  • k == 1
  • vis[u][k]
  • !vis[u][k]
  1. ③处应填( ) {{ select(41) }}
  • k == 0 && d[u][0] < d[v][1]
  • k == 1 && d[u][1] < d[v][1]
  • k == 0 && d[u][0] + w < d[v][1]
  • k == 0 && d[u][0] < d[v][0]
  1. ④处应填( ) {{ select(42) }}
  • d[T][0]
  • d[T][1]
  • min(d[T][0], d[T][1])
  • max(d[T][0], d[T][1])
  1. 若把第 2828 行(if (d[u][k] + w < d[v][k]) 所在行)中的 d[v][k] 误写为 d[v][0],则程序( )。 {{ select(43) }}
  • 输出不变
  • 11 层的距离不再被正确更新,答案可能偏大
  • 一定输出 00
  • 会陷入死循环