GESP 客观题评测系统

试卷解析 · 理解每一步

洛谷 SCP-S 2024 第一轮模拟赛(提高级 C++)

CSPS-2024-R1-Mock-Luogu

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

一、单项选择题

第 1 题(单选题,2 分)

下列编译命令,是 CSP-S 第二轮评测时用于编译题目英文名为 luogu 的传统型试题的选手代码的是( )。

A.
gcc -std=c++14 -O2 -o * luogu.cpp
B.
g++ -std=c++14 -O2 -o * luogu.cpp
C.
g++ -O2 -o * luogu.cpp
D.
g++ -std=c++14 -o * luogu.cpp

正确答案B

解析详情
答案 BC++ 编译命令
思路与推导
  1. C++ 源文件应由 `g++` 编译,并显式采用 C++14 标准;评测常用 `-O2` 开启二级优化,再由 `-o` 指定输出文件。因此应选 B。

第 2 题(单选题,2 分)

在 2023 年的 CSP-S 第二轮认证中,有四位同学对于某一题得 0 分的情况提出了申诉。根据 CCF NOI 竞赛委员会的相关规定,下列申诉中可能被接受的是()。

A.
小明在提交的程序中并未删除用于输出调试信息的代码。
B.
小红在提交的程序中使用了随机化算法。
C.
小黄提交的程序在考场的 Windows 电脑上正常编译,而在最终评测时编译失败。
D.
小陈在与评测环境相同的电脑上运行程序,使用了 850 毫秒运行得出正确答案,而该题的时间限制为 1 秒。程序运行并未超出内存限制。

正确答案D

解析详情
答案 DCSP 评测与申诉规则
思路与推导
  1. 调试输出、随机化算法的偶然结果以及只在考场 Windows 环境通过,均属于选手应自行承担的程序问题。D 中程序在与评测环境相同的机器上以 850 毫秒完成且低于 1 秒限制,存在评测异常的可能,因而申诉可能被接受。

第 3 题(单选题,2 分)

大型语言模型(LLM)指使用大量文本数据训练的深度学习模型,它们可以生成自然语言文本或理解语言文本的含义。下列人工智能技术的应用中,不属于 LLM 的是()。

A.
ChatGPT
B.
Stable Diffusion
C.
Gemini
D.
文心一言

正确答案B

解析详情
答案 B生成式人工智能模型分类
思路与推导
  1. ChatGPT、Gemini 和文心一言的核心能力都建立在大型语言模型上。Stable Diffusion 主要是面向图像生成的扩散模型,不属于大型语言模型。

第 4 题(单选题,2 分)

(47) 10_{10} 与下列()选项表示的数值一致?

A.
(56)8(56)_{8}
B.
(1100110)2(1100110)_{2}
C.
(142)5(142)_{5}
D.
(2D)16(2D)_{16}

正确答案C

解析详情
答案 C进制转换
思路与推导
  1. (142)5=1×52+4×5+2=25+20+2=47(142)_5=1\times5^2+4\times5+2=25+20+2=47,与 (47)10(47)_{10} 相等。容易混淆的 (2D)16=2×16+13=45(2D)_{16}=2\times16+13=45。

第 5 题(单选题,2 分)

定义 aa 在模 pp 意义下的乘法逆元为同余方程 ax≡1( mod p)ax \equiv 1(\bmod p) 的解 xx。请计算 13 在模 29 意义下的乘法逆元是( )。

A.
11
B.
10
C.
8
D.
9

正确答案D

解析详情
答案 D模意义下的乘法逆元
思路与推导
  1. 验证 13×9=117=4×29+113\times9=117=4\times29+1,故 13×9≡1(mod29)13\times9\equiv1\pmod{29},所以 13 模 29 的乘法逆元为 9。

第 6 题(单选题,2 分)

仿照二项式系数,定义三项式系数 TnkT_n^k 为 (1+x+x2)n(1 + x + x^2)^n 的展开式中 xkx^k 项的系数。即: (1+x+x2)n=Tn0+Tn1x1+Tn2x2+⋯+Tn2nx2n(1 + x + x^2)^n = T_n^0 + T_n^1 x^1 + T_n^2 x^2 + \cdots + T_n^{2n} x^{2n}。现要计算 T80+T81+T82+⋯+T816T_8^0 + T_8^1 + T_8^2 + \cdots + T_8^{16} 的值,其结果为( )?

A.
4096
B.
6561
C.
8192
D.
15625

正确答案B

解析详情
答案 B多项式系数和
思路与推导
  1. 所求是 (1+x+x2)8(1+x+x^2)^8 的全部系数之和,令 x=1x=1 即得 (1+1+1)8=38=6561(1+1+1)^8=3^8=6561。

第 7 题(单选题,2 分)

当在二叉排序树中插入一个新结点时,若树中不存在与待插入结点关键字相同的结点,且待插入结点的关键字小于根结点的关键字,则新结点将成为根结点的( )?

A.
左子树的某一叶子结点
B.
右子树的某一叶子结点
C.
左子树的某一非叶子结点
D.
右子树的某一非叶子结点

正确答案A

解析详情
答案 A二叉排序树插入
思路与推导
  1. 待插入关键字小于根关键字,第一次比较后必进入根的左子树;继续比较直到遇到空指针,新结点总是作为该位置的叶子结点插入。因此它是左子树中的某个叶子结点。

第 8 题(单选题,2 分)

一个盒子里有4个红球、5个蓝球和6个绿球。现在从盒子里随机抽取3个球,则这3个球中恰好有1个红球、1个蓝球和1个绿球的概率是()。

A.
136/455
B.
24/91
C.
5/66
D.
1/11

正确答案B

解析详情
答案 B古典概率与组合计数
思路与推导
  1. 有利取法为 (41)(51)(61)=120\binom{4}{1}\binom{5}{1}\binom{6}{1}=120,全部取法为 (153)=455\binom{15}{3}=455。所求概率为 120/455=24/91120/455=24/91。

第 9 题(单选题,2 分)

对前缀表达式 - + 10 * 2 3 + 5 / 6 2 进行求值,得到的结果是()。

A.
8
B.
9
C.
10
D.
11

正确答案A

解析详情
答案 A前缀表达式求值
思路与推导
  1. 表达式对应 (10+2×3)−(5+6/2)(10+2\times3)-(5+6/2)。两部分分别为 16 和 8,所以结果为 16−8=816-8=8。

第 10 题(单选题,2 分)

已知一个循环队列的存储空间为数组 data q[21] 且不浪费空间。且在队列的定义中,头指针指向队列的开头,尾指针指向队列末尾的下一个元素。现在若头指针和尾指针分别指向下标 8 和 3,则队列当前的长度为( )?

A.
5
B.
6
C.
17
D.
16

正确答案D

解析详情
答案 D循环队列长度计算
思路与推导
  1. 数组容量为 21,且尾指针指向队尾后一格,因此队长为 (tail−head+21) mod 21=(3−8+21) mod 21=16(tail-head+21)\bmod21=(3-8+21)\bmod21=16。

第 11 题(单选题,2 分)

在使用下列算法对整数数列进行排序时,哪一个算法的运行时间复杂度与整数大小无关()。

A.
基数排序
B.
计数排序
C.
希尔排序
D.
以上排序算法的运行时间复杂度均与整数大小有关

正确答案C

解析详情
答案 C排序算法复杂度
思路与推导
  1. 希尔排序的运行过程由元素个数、增量序列和比较结果决定,不把整数的数值范围或位数作为复杂度参数。计数排序依赖值域大小,基数排序依赖数字位数,因此选 C。

第 12 题(单选题,2 分)

假设变量 a, b, c 均为绝对值不超过 10910^9 的 32 位有符号整型变量,下列关于这三个变量,说法正确的是( )。

A.
若执行代码 auto d = a * b;则 d 的变量类型是 64 位有符号整型变量。
B.
逻辑表达式 max⁡(a,b)∗1LL∗c==max⁡(1LL∗a∗c,1LL∗b∗c)\max(a, b) * 1LL * c == \max(1LL * a * c, 1LL * b * c) 的运算结果一定为真。
C.
执行代码 cout << sizeof(a);后,输出的结果为 4。
D.
for (unsigned i = a; i < b; i++) 可能是一个死循环。

正确答案C

解析详情
答案 CC++ 整型、类型推导与溢出
思路与推导
  1. 题设明确 `a` 是 32 位有符号整型,因此 `sizeof(a)` 为 4 字节。`auto d=a*b` 仍先按 `int` 运算并推导为 `int`;当 `c<0` 时乘法会反转大小关系,故含 `max` 的等式也不恒成立。

第 13 题(单选题,2 分)

对于以下代码,假设执行单次 `rand()` 的时间复杂度为 O(1)O(1),那么 `calc` 函数的运行时间复杂度为( )?

unsigned int ans = 0;
void val(int n) {
    for (int i = 1; i <= n; ++i)
        for (int j = 0; j < n; j += i)
            ans += rand();
}

void calc(int n) {
    if (n <= 1) val(n);
    else calc(n / 2), calc(n / 2), val(n);
}
A.
Θ(n)\Theta(n)
B.
Θ(nlog⁡n)\Theta(n\log n)
C.
Θ(nlog⁡2n)\Theta(n\log^2 n)
D.
Θ(nlog⁡3n)\Theta(n\log^3 n)

正确答案C

解析详情
答案 C调和级数与主定理
思路与推导
  1. `val(n)` 的内层循环次数为 ∑i=1n⌈n/i⌉=Θ(nlog⁡n)\sum_{i=1}^{n}\lceil n/i\rceil=\Theta(n\log n)。于是 `calc` 满足 T(n)=2T(n/2)+Θ(nlog⁡n)T(n)=2T(n/2)+\Theta(n\log n);递归树各层求和后得到 Θ(nlog⁡2n)\Theta(n\log^2 n)。

第 14 题(单选题,2 分)

给定一个无向图 G,其中包含以下顶点和边:

顶点集合: V={A,B,C,D,E}V = \{A, B, C, D, E\}

边集合: E={(A,B),(A,C),(B,C),(B,D),(C,D),(C,E)}\mathrm{E} = \{(\mathrm{A}, \mathrm{B}), (\mathrm{A}, \mathrm{C}), (\mathrm{B}, \mathrm{C}), (\mathrm{B}, \mathrm{D}), (\mathrm{C}, \mathrm{D}), (\mathrm{C}, \mathrm{E})\}

请问以下哪一个选项正确描述了图 G 的双连通性?( )。

A.
图 G 是点双连通的,因为删除任意一个顶点后,图仍然连通。
B.
图 G 不是点双连通的,因为存在割点。
C.
图 G 是边双连通的,因为存在至少两个顶点的简单环。
D.
图 G 不是边双连通的,因为删除任意一条边后,图不再连通。

正确答案B

解析详情
答案 B割点与点双连通
思路与推导
  1. 顶点 E 只通过边 (C,E)(C,E) 与其余图相连;删除 C 后,E 与其他顶点断开,所以 C 是割点,图 G 不是点双连通图。

第 15 题(单选题,2 分)

使用哈希表存储元素 19,53,49,114,为了让哈希表不发生哈希冲突,可以使用( )选项的哈希函数?(定义: [x][x] 为不超过 xx 的最大整数,如 [3.14]=3[3.14] = 3)

A.
f(x)=xmod  17f(x) = x \mod 17
B.
f(x)=[x]f(x) = [\sqrt{x}]
C.
f(x)=[100lg⁡x]f(x) = [100 \lg x]
D.
f(x)=x2mod  13f(x) = x^2 \mod 13

正确答案C

解析详情
答案 C哈希函数与冲突
思路与推导
  1. 对 C 中的函数计算可得 ⌊100lg⁡19⌋=127\lfloor100\lg19\rfloor=127、⌊100lg⁡53⌋=172\lfloor100\lg53\rfloor=172、⌊100lg⁡49⌋=169\lfloor100\lg49\rfloor=169、⌊100lg⁡114⌋=205\lfloor100\lg114\rfloor=205,四个地址互不相同。其余函数至少会让 19 与 53 或 49 与 114 发生冲突。

二、阅读程序(1)

#include <bits/stdc++.h>
using namespace std;

set<int> s1 = {1, 2, 3}, s2 = {2, 3, 1, 1},
         s3 = {1, 2, 100}, s4 = {3, 4, 5};
map<set<int>, int> mp1, mp2;

set<int> intersection(set<int> a, set<int> b) {
    if (a.size() > b.size()) swap(a, b);
    set<int> res = a;
    for (int i : a)
        if (b.count(i) == 0)
            res.erase(i);
    return res;
}

int main() {
    cout << (s1 == s2) << endl;
    mp1[s3] = 9; mp1[s1] = 1;
    mp2[s2] = 1; mp2[s4] = 5;
    cout << (mp1 < mp2) << ' ';
    cout << mp2[s3] << ' ';
    cout << (mp1 <= mp2) << endl;
    mp1.clear();
    int n, l, t;
    cin >> n;
    for (int i = 1; i <= n; i++) {
        set<int> tmp;
        for (cin >> l; l; l--) {
            cin >> t;
            tmp.emplace(t);
        }
        mp1[tmp] = i;
    }
    set<int> res = mp1.begin()->first;
    for (auto i : mp1)
        res = intersection(i.first, res);
    cout << res.size();
    return 0;
}

第 16 题(判断题,1.5 分)

代码运行后,输出的第一行是 0。()

正确答案错误

解析详情
答案 错误`std::set` 的去重与比较
思路与推导
  1. `s2` 初始化时重复的 1 会被去重,且集合自动有序,因此 `s1` 与 `s2` 都等于 `{1,2,3}`。表达式 `s1 == s2` 为真,第一行输出 1 而不是 0。

第 17 题(判断题,1.5 分)

设集合 a, b 的元素个数分别为 p, q,则执行函数 intersection(a,b) 的时间复杂度为 Θ(min⁡(p,q)log⁡max⁡(p,q))\Theta(\min(p,q)\log\max(p,q))。()

正确答案错误

解析详情
答案 错误`std::set` 操作复杂度
思路与推导
  1. `a`、`b` 按值传参,复制两个集合本身就需要 Θ(p+q)\Theta(p+q);随后还要遍历较小集合,并执行 `count` 和可能的 `erase`。例如 p=1,qp=1,q 很大时,实际时间至少为 Θ(q)\Theta(q),而题述只有 Θ(log⁡q)\Theta(\log q)。

第 18 题(判断题,1.5 分)

将第32行的begin()换成rbegin(),运行结果可能改变。()

正确答案错误

解析详情
答案 错误集合交的结合性
思路与推导
  1. 循环最终把 `res` 与 `mp1` 中每一个键集合都取交集。初值无论选最小键 `begin()->first` 还是最大键 `rbegin()->first`,它本身也会参与循环,最终结果都是所有键集合的交集。

第 19 题(判断题,1.5 分)

将第 33 行的 auto 换成 pair <set <int>, int>, 运行结果不变。()

正确答案正确

解析详情
答案 正确范围 `for` 与类型推导
思路与推导
  1. `mp1` 的元素可转换并复制为 `pair<set<int>, int>`;循环体只读取副本 `i.first`,没有依赖键的 `const` 限定,也不修改映射。因此把 `auto` 换成该显式类型不改变结果。

第 20 题(单选题,3 分)

输出的第二行是()。

A.
0 0 0
B.
1 0 1
C.
0 1 1
D.
1 0 0

正确答案D

解析详情
答案 D`map` 的字典序比较与下标访问
思路与推导
  1. `mp1` 与 `mp2` 的首项均为 `{1,2,3}:1`,第二项比较时 `{1,2,100}<{3,4,5}`,故 `mp1<mp2` 输出 1。`mp2[s3]` 插入值 0;再次比较时同为键 `s3` 而值 9>09>0,所以 `mp1<=mp2` 输出 0,整行为 `1 0 0`。

第 21 题(单选题,3 分)

记所有输入的1之和为L,则该程序最坏情况下的时间复杂度是()?

A.
Θ(Llog⁡L)\Theta(L \log L)
B.
Θ(Llog⁡2L)\Theta(L \log^{2} L)
C.
Θ(nLlog⁡L)\Theta(nL\log L)
D.
Θ(nLlog⁡nlog⁡L)\Theta(nL\log n\log L)

正确答案A

解析详情
答案 A关联容器的总复杂度
思路与推导
  1. 读入的 LL 个元素插入 `set`,总计至多 Θ(Llog⁡L)\Theta(L\log L);把集合插入 `map` 以及逐集合求交,同样可由 LL 次量级的平衡树查找、插入或删除控制。最坏情况下总复杂度为 Θ(Llog⁡L)\Theta(L\log L)。

二、阅读程序(2)

#include <bits/stdc++.h>
using namespace std;

constexpr int mod = 998244353;
int n, k, a[12], b[12], ans[12], fa[12];

int findfa(int u) { return u == fa[u] ? u : fa[u] = findfa(fa[u]); }

int functionUnknown(int a[], int n) {
    if (n <= 1) return 0;
    int i = n - 1, j, k;
    while (true) {
        j = i; --i;
        if (a[i] < a[j]) {
            for (k = n; a[i] >= a[--k];);
            swap(a[i], a[k]);
            reverse(a + j, a + n);
            return 1;
        }
        if (!i) {
            reverse(a, a + n);
            return 0;
        }
    }
    return -1;
}

int F(int x) {
    int ans = 0;
    for (int i = k - 1; ~i; --i)
        ans = (1ll * ans * x % mod + a[i]) % mod;
    return ans;
}

int main() {
    scanf("%d %d", &n, &k);
    for (int i = 0; i < k; ++i) scanf("%d", a + i);
    for (int m = 1; m <= n; ++m) {
        for (int i = 0; i < m; ++i) b[i] = i;
        do {
            for (int i = 0; i < m; ++i) fa[i] = i;
            int res = m;
            for (int i = 0, u, v; i < m; ++i) {
                u = findfa(i); v = findfa(b[i]);
                if (u == v) continue;
                --res; fa[u] = v;
            }
            int flag = 0;
            for (int i = 0; i < m; ++i)
                if (b[i] == i) flag = 1;
            if (flag) continue;
            ans[m] = (ans[m] + F(res)) % mod;
        } while (functionUnknown(b, m));
        printf("%d%c", ans[m], " 
"[m == n]);
    }
    return 0;
}

第 22 题(判断题,1.5 分)

functionUnknown 函数的返回值不可能为 -1。()

正确答案正确

解析详情
答案 正确`next_permutation` 的控制流程
思路与推导
  1. 当 n≤1n\le1 时函数直接返回 0;否则 `while(true)` 中要么找到下一排列并返回 1,要么确认已是最大排列、翻转后返回 0。循环后的 `return -1` 永远不可达。

第 23 题(判断题,1.5 分)

当输入的 k=1 时,输出的数值均能表示为 t×a[0]t \times a[0] 的形式,其中 t 是一个整数。()

正确答案错误

解析详情
答案 错误取模对整除性的影响
思路与推导
  1. k=1k=1 时确有 `F(res)=a[0]`,但 `ans[m]` 每次累加后都会模 998244353,取模会破坏“是 `a[0]` 的整数倍”这一性质。例如 m=5,a[0]=108m=5,a[0]=10^8 时,44a[0] mod 998244353=40702258844a[0]\bmod998244353=407022588,并非 10810^8 的整数倍。

第 24 题(判断题,1.5 分)

如果把第34行整行改为b[m - 1] = m - 1,则程序输出将会被改变。()

正确答案错误

解析详情
答案 错误全排列枚举的循环不变量
思路与推导
  1. 原第 34 行把 `b[0..m-1]` 初始化为升序。上一轮枚举结束时,`functionUnknown` 已把前 m−1m-1 项从最大排列翻回升序;再执行 `b[m-1]=m-1` 后,长度 mm 的数组仍恰为升序初始排列,所以输出不变。

第 25 题(单选题,3 分)

在主函数中,findfa 函数被调用的次数与以下哪个选项同阶()。

A.
Θ(n!)\Theta(n!)
B.
Θ(n!n)\Theta(n!n)
C.
Θ(n!n2)\Theta(n!n^2)
D.
Θ(n!n3)\Theta(n!n^3)

正确答案B

解析详情
答案 B全排列枚举与并查集
思路与推导
  1. 固定 mm 时共有 m!m! 个排列;每个排列的长度为 mm,循环中对每个 `i` 显式调用两次 `findfa`,调用量与 m⋅m!m\cdot m! 同阶。对 m=1m=1 到 nn 求和由末项支配,得到 Θ(n⋅n!)\Theta(n\cdot n!)。

第 26 题(单选题,3 分)

对于以下的输入数据,输出结果为( )。

5 5

1 2 3 4 5

A.
0 15 30 261 1500
B.
0 12 24 297 1788
C.
0 15 30 477 2940
D.
0 15 30 864 5520

正确答案C

解析详情
答案 C排列环分解与多项式求值
思路与推导
  1. `res` 是排列的环数,且 F(x)=1+2x+3x2+4x3+5x4F(x)=1+2x+3x^2+4x^3+5x^4,所以 F(1)=15,F(2)=129F(1)=15,F(2)=129。m=4m=4 的无不动点排列含 6 个四环和 3 个双二环,得 6F(1)+3F(2)=4776F(1)+3F(2)=477;m=5m=5 含 24 个五环和 20 个“三环+二环”,得 24F(1)+20F(2)=294024F(1)+20F(2)=2940,整行是 `0 15 30 477 2940`。

第 27 题(单选题,3 分)

functionUnknown 的功能接近于 C++ STL 库中的以下()函数。

A.
next_permutation
B.
prev_permutation
C.
is_sorted
D.
is_permutation

正确答案A

解析详情
答案 A字典序下一排列
思路与推导
  1. 函数从右向左找首个上升位置,交换右侧恰好更大的元素,再反转后缀,得到字典序的下一个排列;若不存在上升位置,则把整个序列翻为最小排列并返回 0。这正是 `next_permutation` 的行为。

二、阅读程序(3)

#include <bits/stdc++.h>
using namespace std;

unsigned f(unsigned x) {
    x ^= x << 3;
    x ^= x >> 5;
    return x;
}

unsigned g(unsigned x) {
    return (x >> 5) ^ (x >> 2) ^ x ^ (x << 3);
}

int main() {
    unsigned y, l, r;
    cin >> y >> l >> r;
    for (unsigned long long i = l; i <= r; i++)
        if (f(i) == y)
            cout << i % 11 << endl;
    return 0;
}

第 28 题(判断题,1.5 分)

若输入为 `2024 1 -1`,那么程序将不会输出任何数字。( )

正确答案错误

解析详情
答案 错误无符号整数转换与异或移位逆运算
思路与推导
  1. 读入 `-1` 时,无符号变量 `r` 得到 232−12^{32}-1,循环覆盖全部 32 位无符号数。两次 `x ^= shift` 都是可逆变换;对 y=2024y=2024 求逆得到唯一的 i=230i=230,程序会输出 230 mod 11=10230\bmod11=10。

第 29 题(判断题,1.5 分)

若把第14行i的类型改为unsigned int,则程序可能无法结束运行。()

正确答案正确

解析详情
答案 正确无符号整数溢出
思路与推导
  1. 若 `i` 改为 32 位 `unsigned int` 且 `r=4294967295`,当 `i` 取到最大值后执行 `i++` 会回绕为 0。此后条件 `i<=r` 始终成立,循环无法结束。

第 30 题(判断题,1.5 分)

对于所有符合要求的输入,输出的数字不可能超过一个。()

正确答案正确

解析详情
答案 正确异或移位变换的可逆性
思路与推导
  1. 在固定 32 位上,`x ^= x << 3` 和 `x ^= x >> 5` 都可由低位到高位或由高位到低位逐位还原,因此 `f` 是双射。给定 `y` 只有一个 32 位原像,区间 `[l,r]` 中至多命中一次。

第 31 题(单选题,3 分)

若从所有 unsigned int 当中随机均匀选取一个 x,则 f(x)=g(x) 成立的概率和()的差最小。

A.
0
B.
115\frac{1}{15}
C.
12\frac{1}{2}
D.
1

正确答案B

解析详情
答案 B位运算的线性展开与概率
思路与推导
  1. 展开可知 `f(x)` 与 `g(x)` 只在 `(x<<3)>>5` 相比 `x>>2` 丢失的 3 个高位贡献上不同,因此相等当且仅当 `x` 的最高 3 位全为 0,概率为 1/81/8。它与 1/151/15 的差为 7/1207/120,小于与 0、1/21/2、1 的差。

第 32 题(单选题,4 分)

定义 fn(x)f^n(x) 表示对 xx 用函数 ff 作用 nn 次的结果,例如 f2(x)=f(f(x))f^2(x) = f(f(x))。

假设 unsigned 类型具有 ω\omega 个二进制位,且已知存在某种计算 fn(x)f^n(x) 的算法的时间复杂度为 Θ(T(n)P(ω))\Theta(T(n)P(\omega)),其中 P(ω)P(\omega) 是一个关于 ω\omega 的幂函数。则 T(n)T(n) 最小是( )?

A.
Θ(1)\Theta(1)
B.
Θ(log⁡n)\Theta(\log n)
C.
Θ(log⁡2n)\Theta(\log^2 n)
D.
Θ(n)\Theta(n)

正确答案B

解析详情
答案 B线性变换快速幂
思路与推导
  1. `f` 是 ω\omega 位向量空间上的线性变换,可表示为 ω×ω\omega\times\omega 的二进制矩阵。用二进制快速幂计算该矩阵的 nn 次幂,需要 Θ(log⁡n)\Theta(\log n) 次矩阵合成,每次代价由关于 ω\omega 的幂函数吸收,因此最小的 T(n)T(n) 为 Θ(log⁡n)\Theta(\log n)。

第 33 题(单选题,3 分)

当输入为 50 1 4294967295 时,输出的第一个数是()。

A.
1
B.
8
C.
9
D.
10

正确答案D

解析详情
答案 D异或移位的逆变换
思路与推导
  1. 令 z=x⊕(x≪3)z=x\mathbin{\oplus}(x\ll3),由 50=z⊕(z≫5)50=z\mathbin{\oplus}(z\gg5) 逐段恢复得 z=51z=51;再逆向恢复 x⊕(x≪3)=51x\mathbin{\oplus}(x\ll3)=51,得唯一原像 x=1840700267x=1840700267。于是首个输出为 x mod 11=10x\bmod11=10。

三、完善程序(1)

(1)(最小垄断集)问题:你有一张 n 个结点(结点编号从 1 到 n),m 条边的无问无权图 G=(V,E)G = (V, E),其中 V 为点集,E 为边集。称 V 的一个子集 S 垄断了图 G,当且仅当 ∀(u,v)∈E\forall (u, v) \in E,u, v 中必然恰有一个结点在 S 内。求垄断了 G 的子集 S 至少有多少个元素,或报告不存在这样的子集。试补全程序。

#include <bits/stdc++.h>
using namespace std;

int n, m, is[100005];
vector<int> g[100005];
queue<int> q;

int main() {
    cin >> n >> m;
    for (int i = 1; i <= m; i++) {
        int u, v;
        cin >> u >> v;
        g[u].emplace_back(v);
        g[v].emplace_back(u);
    }
    int tot = 0;
    for (int k = 1; k <= n; k++) {
        if (①) continue;
        q.emplace(k);
        is[k] = 1;
        int cnt[3] = ②;
        while (q.size()) {
            for (int i = 0; i < g[q.front()].size(); i++) {
                int to = g[q.front()][i];
                if (is[to] == 0) {
                    is[to] = ③;
                    cnt[is[to]]++;
                    q.emplace(to);
                } else if (④) {
                    puts("No such subset."); // 报告不存在这样的子集
                    return 0;
                }
            }
            q.pop();
        }
        tot += ⑤;
    }
    cout << tot;
    return 0;
}

第 34 题(单选题,3 分)

①处应填( )

A.
is[k]
B.
is[k] == 0
C.
q.empty()
D.
tot > k

正确答案A

解析详情
答案 A连通分量遍历与二分图染色
思路与推导
  1. `is[v]=0` 表示未访问,1、2 表示二分图的两种颜色。外层枚举到已经染色的顶点时,应以 `if (is[k]) continue` 跳过,保证每个连通分量只启动一次 BFS。

第 35 题(单选题,3 分)

②处应填()

A.
{0, 0, 0}
B.
{0, 0, 1}
C.
{1, 0, 0}
D.
{0, 1, 0}

正确答案D

解析详情
答案 D二分图两侧点数统计
思路与推导
  1. 每个新连通分量从顶点 `k` 开始,并已执行 `is[k]=1`,所以颜色 1 的计数初值为 1,颜色 2 为 0;`cnt[0]` 不参与答案,故应初始化为 `{0,1,0}`。

第 36 题(单选题,3 分)

③处应填( )

A.
is[q.front()]
B.
3 - is[q.front()]
C.
!is[q.front()]
D.
q.front()

正确答案B

解析详情
答案 BBFS 二分图染色
思路与推导
  1. 每条边的两个端点必须恰有一个属于集合,相邻点必须染成不同颜色。颜色只取 1 和 2,因此未访问邻点 `to` 应赋为 `3-is[q.front()]`,在 1 与 2 之间切换。

第 37 题(单选题,3 分)

④处应填( )。

A.
is[to] == is[q.front()]
B.
is[to] != is[q.front()]
C.
is[to] && is[q.front()]
D.
abs(is[to] - is[q.front()]) == 1

正确答案A

解析详情
答案 A二分图冲突判定
思路与推导
  1. 若 `to` 已经染色,则当前边合法的条件是两端颜色不同;一旦 `is[to]==is[q.front()]`,该连通分量含奇环,无法让每条边恰有一个端点进入 SS,应立即报告无解。

第 38 题(单选题,3 分)

⑤处应填( )。

A.
cnt[1]
B.
min(cnt[0], cnt[1])
C.
min(cnt[1], cnt[2])
D.
cnt[1] + cnt[2]

正确答案C

解析详情
答案 C二分图最小点侧选择
思路与推导
  1. 一个合法连通分量的集合 SS 必须恰好取二分图的一侧;交换两种颜色仍然合法。为使元素数最少,应在该分量贡献 min⁡(cnt[1],cnt[2])\min(cnt[1],cnt[2]),各分量再累加。

三、完善程序(2)

(2)(最长公共前缀)定义 LCP(s,t)为两个字符串的最长公共前缀。例如:s=abcde,t=abcabc,则 LCP(s,t)=abc。定义|s|为字符串s的长度,在上一例中|s|=5。

现在给定了 n 个字符串 s1,s2,…,sns_1, s_2, \ldots, s_n。现在需要统计所有同时满足如下两个条件的

∣LCP(si,sj)∣\left| \text{LCP}(s_i, s_j) \right| 之和对 998244353 取模的值:条件 1:i < j。条件 2: si<sjs_i < s_j。

若 1≤n≤2×1051 \leq n \leq 2 \times 10^5, 1≤∣si∣≤201 \leq |s_i| \leq 20,字符串仅由小写字母构成,试补全程序。

#include <bits/stdc++.h>
using namespace std;

const int maxn = 2e5 + 9, mod = 998244353;
char s[maxn][22];
int n;
int tmp[27][maxn], a[maxn];

int dfs(int l, int r, int p) {
    if (l >= r || p >= 20) return 0;
    int tail[27], ans = 0;
    memset(tail, 0, sizeof(tail));
    for (int i = l; i <= r; ++i) {
        int ch = ①;
        ②;
        for (int j = 0; j < ch; ++j)
            ③;
    }
    int tot = l, pos = l;
    for (int i = 0; i < 27; ++i)
        for (int j = 0; j < tail[i]; ++j)
            a[tot++] = tmp[i][j];
    for (int i = 0; i < 27; ++i) {
        ④;
        pos += tail[i];
    }
    return ans;
}

int main() {
    scanf("%d", &n);
    for (int i = 1; i <= n; ++i) scanf("%s", s[i]);
    for (int i = 1; i <= n; ++i) a[i] = i;
    printf("%d
", ⑤);
    return 0;
}

第 39 题(单选题,3 分)

①处应填( )

A.
s[i][p] ? s[i][p] - 'a' : 0
B.
s[i][p] ? s[i][p] - 'a' + 1 : 0
C.
s[a[i]][p] ? s[a[i]][p] - 'a' : 0
D.
s[a[i]][p] ? s[a[i]][p] - 'a' + 1 : 0

正确答案D

解析详情
答案 D字符串分桶与哨兵编码
思路与推导
  1. `a[i]` 才是当前位置对应的原字符串编号,所以要读取 `s[a[i]][p]`。字符串结束符必须映射为 0,字母 `a` 到 `z` 映射为 1 到 26,故表达式为 `s[a[i]][p] ? s[a[i]][p]-'a'+1 : 0`。

第 40 题(单选题,3 分)

②处应填( )

A.
tmp[ch][tail[ch]++] = a[i]
B.
tmp[ch][++tail[ch]] = a[i]
C.
tmp[ch][tail[ch]++] = i
D.
tmp[ch][++tail[ch]] = i

正确答案A

解析详情
答案 A稳定计数分桶
思路与推导
  1. 当前字符串编号是 `a[i]`,应写入字符桶 `tmp[ch]`;`tail[ch]` 既表示桶长又作为从 0 开始的下标,因此先写 `tmp[ch][tail[ch]]` 再自增,即 `tmp[ch][tail[ch]++]=a[i]`。这也保持了同桶元素的原下标顺序。

第 41 题(单选题,3 分)

③处应填( )

A.
ans = (ans + 1ll * (p - 1) * tail[j] % mod) % mod
B.
ans = (ans + 1ll * p * tail[j] % mod) % mod
C.
ans = (ans + 1ll * (p + 1) * tail[j] % mod) % mod
D.
ans = (ans + 1ll * (p + 2) * tail[j] % mod) % mod

正确答案B

解析详情
答案 B最长公共前缀的分治计数
思路与推导
  1. 处理到位置 pp 时,当前段内字符串已有长度 pp 的公共前缀。对当前字符为 `ch` 的字符串,先前位于桶 `j<ch` 的每个字符串都满足原下标更小、字典序也更小,且二者恰在位置 pp 首次不同,所以每对贡献 pp,应累加 `p*tail[j]`。

第 42 题(单选题,3 分)

④处应填()。

A.
ans = (ans + dfs(pos + 1, pos + tail[i], p + 1)) % mod
B.
ans = (ans + dfs(pos + 1, pos + tail[i], p - 1)) % mod
C.
ans = (ans + dfs(pos, pos + tail[i] - 1, p + 1)) % mod
D.
ans = (ans + dfs(pos, pos + tail[i] - 1, p - 1)) % mod

正确答案C

解析详情
答案 C按字符分治递归
思路与推导
  1. 重排后,第 `i` 个字符桶恰占半闭区间意义下的连续段 `[pos,pos+tail[i])`,转换为函数的闭区间参数就是 `dfs(pos,pos+tail[i]-1,p+1)`。只有当前字符相同的字符串才需进入下一位继续比较;总深度至多 20。

第 43 题(单选题,3 分)

⑤处应填()。

A.
dfs(0, n - 1, 0)
B.
dfs(1, n, 0)
C.
dfs(1, n, 1)
D.
dfs(1, n - 1, 1)

正确答案B

解析详情
答案 B递归入口与字符串下标
思路与推导
  1. 主程序把 `a[1..n]` 初始化为对应字符串编号,尚未比较任何字符,所以初始区间是 `[1,n]`,字符位置是 0,应调用 `dfs(1,n,0)`。每层稳定分桶且字符串长度至多 20,整体处理量为 O(20n)O(20n) 量级。