试卷解析 · 理解每一步
洛谷 SCP-S 2023 第一轮模拟赛(提高级 C++)
CSPS-2023-R1-Mock-Luogu
试卷解析总览,可直接查看每题答案与解析。
第 1 题(单选题,2 分)
以下物品可以携带进 CSP 第二轮测试考场的是()。
正确答案D
解析详情
计算器属于电子计算工具,印有完整代码的衣物属于可供抄录的程序资料,背包也不应带入考场座位。普通食品不具备计算或资料存储功能,因此可携带的是烤鸡柳。
第 2 题(单选题,2 分)
在 CSP 第二轮测试中,老 A 发现小 K 正在使用某种技术手段(比如 SSH)抄袭自己的代码,若老 A 未及时举报小 K 的行为,且比赛结束后查出两人代码雷同,且有证据证明老 A 对此事知情,则老 A 与小 K 分别受到的惩罚禁赛时间为:( )。
正确答案A
解析详情
小 K 主动通过 SSH 抄袭,构成作弊;老 A 明知代码被抄却未及时举报,属于知情配合。按题目所依据的 CSP 纪律规定,两人均禁赛三年。
第 3 题(单选题,2 分)
「流程结构」是编程中用于控制程序执行流程的一种方式。它包括顺序结构、分支结构和循环结构。在一些诗歌作品中,也有对「流程结构」的体现。下列诗歌片段中体现循环结构的是()。
正确答案B
解析详情
“只要……就一直……”表示条件成立时持续重复同一动作,对应 while 型循环。A、D 主要体现条件分支,C 是按时间先后执行的顺序结构。
第 4 题(单选题,2 分)
以下四种编程语言中,属于弱类型编程语言的是:
正确答案D
解析详情
C++ 允许较多隐式类型转换,例如整数、浮点数和布尔值之间可自动转换,因而在这组语言中通常归为弱类型。Java、Go 和 Rust 对不同类型之间的赋值与运算限制更严格。
第 5 题(单选题,2 分)
现有一段长度为3分钟,采样率为44.1千赫兹、位深为16比特的wav文件的双通道立体声音频,该音频文件占用的存储空间大小最接近:()。
正确答案B
解析详情
未压缩 PCM 音频大小为 字节,约为 MiB,因此最接近 30 MiB。
第 6 题(单选题,2 分)
在 vim 编辑器中,若当前位于 normal 模式,你需要将光标移动到这一行的末尾并进入 insert 模式。依次按下以下按键无法实现该目标的是:___。
正确答案A
解析详情
在 normal 模式下,先按 Shift+4 移到行尾再按 `a`,或直接按 `A`,都能在行尾进入 insert 模式;`o` 新建下一行后退格也处于插入状态。`Esc :wq` 执行的是保存并退出,不能完成目标。
第 7 题(单选题,2 分)
在下列四组时空限制中,书写正确且允许使用的内存最多的一组是:()
正确答案D
解析详情
D 使用合法的时间、存储单位, ms 为 2 s,内存为 256 MiB。A 的 256000 KiB 只有 250 MiB,C 的 1024 Mbit 只有 128 MiB,B 的 kg 不是时间单位,所以 D 允许使用的内存最多。
第 8 题(单选题,2 分)
假设某算法的计算时间表示为递推关系式 , ,则算法的时间复杂度为()。
正确答案D
解析详情
令 ,递归规模每层乘以常数 ,故共有 层。第 层代价为 ,这些对数项构成等差量级之和,结果为 。
第 9 题(单选题,2 分)
给定矩阵: 。我们定义一次操作为:选择同行或同列的两个元素,令其中一个加一,另一个减一。下列矩阵中不能通过 A 矩阵进行若干次操作得到的是()。
正确答案D
解析详情
每次让一个元素加 1、另一个减 1,四个元素总和始终保持为 。A、B、C 的元素和均为 10;D 的元素和为 11,必然不可达。同行或同列关系连通,因此总和相同的整数改变量可沿边转移实现。
第 10 题(单选题,2 分)
「平衡三进制」是一种特殊的计数体系,与标准三进制相比,其中用于计数的符码为 -1,0,1,为书写方便,通常使用字母 Z 代替 -1。例如,因为 ,所以十进制的 6 用平衡三进制表示为 1Z0。则十进制的 -11 可用平衡三进制表示为( ):
正确答案D
解析详情
选项 D 的 `ZZ1` 表示 ,正好等于题目给出的十进制数。
第 11 题(单选题,2 分)
竞赛图也叫有向完全图。每对顶点之间都有一条边相连的有向图称为竞赛图。5 个点的无标号竞赛图数是:()。
正确答案D
解析详情
5 个标号点共有 种定向。用 Burnside 引理按 作用计数,恒等置换固定 1024 个,20 个三循环各固定 16 个,24 个五循环各固定 4 个,其余类型固定 0 个,所以无标号数为 。
第 12 题(单选题,2 分)
依次抛出四个六面骰子,按照抛出顺序将骰子上的数值记为 。则 a < b; b > c; c < d 同时成立的概率为( )。
正确答案A
解析详情
总结果数为 。固定满足 的 后, 有 种、 有 种,故有利结果为 ,概率为 。
第 13 题(单选题,2 分)
有 6 堆石子,每堆石子分别有 1,4,7,1,5,4 个。Alice 和 Bob 两人轮流操作。轮到 Alice 时需要选择一堆石子并拿走其中的任意正奇数个,轮到 Bob 时需要选择一堆石子并拿走其中的任意正偶数个,最先无法操作的人判输。下列说法正确的是:()
正确答案A
解析详情
把局面记为各堆剩余石子数和当前行动者;若存在一步能走到对手必败态,则当前为必胜态。按此递推对 做记忆化搜索,Alice 行动时该状态为必胜,Bob 行动时为必败,因此无论谁先手最终均是 Alice 获胜。
第 14 题(单选题,2 分)
阅读以下 C++ 代码片段:
uint32_t Trans(uint32_t x) {
x ^= x << 13; x ^= x >> 17; x ^= x << 5;
return x;
}
void Cycle(uint32_t x) {
uint32_t old = x, cnt = 0;
do {
x = Trans(x); ++cnt;
} while (x != old);
}其中 uint32_t 表示无符号 32 位整数,在大多数环境中等同于 unsigned int。下列说法有误的一项是:( )。
正确答案A
解析详情
三次异或移位在 32 位空间上都是可逆变换,所以 `Trans` 是双射,不同输入不会合并;该组参数使所有非零状态形成长度 的奇周期,0 则是长度 1 的周期。因此 `Cycle` 总会回到初值且计数为奇数,但 `Trans(0)=0`,A 的“必不相同”错误。
第 15 题(单选题,2 分)
观察如下代码片段:
union U{
bool flag1, flag2, flag3, flag4, flag5;
signed short a;
unsigned short b;
enum E{
CardA = 0, CardB = 1,
CardC = 2, CardD = 142857
} e;
} u;其中, 的值为()。
正确答案A
解析详情
union 的所有成员共享同一段存储,其大小取能容纳最大成员并满足最严格对齐的值。此处 `bool` 为 1 字节、`short` 为 2 字节,枚举通常按 `int` 存储为 4 字节,因此 `sizeof(u)=4`。
二、阅读程序(1)
#include <iostream>
using namespace std;
int a[100005], b[100005], n, m;
void very_quick_sort(int l, int r, int p, int q) {
if (l >= r || p > q) { // ①
return;
}
int mid = (l + r) / 2;
int p0 = p - 1;
int q0 = q + 1;
for (int i = p; i <= q; i++) {
if (a[i] > mid) b[++p0] = a[i];
else b[--q0] = a[i];
}
for (int i = p; i <= q; i++)
a[i] = b[i];
very_quick_sort(mid + 1, r, p, p0);
very_quick_sort(l, mid, q0, q);
}
int main() {
cin >> n >> m;
for (int i = 1; i <= n; i++)
cin >> a[i];
very_quick_sort(1, m, 1, n);
// ②
for (int i = 1; i <= n; i++)
cout << a[i] << " ";
cout << endl;
return 0;
}第 16 题(判断题,1 分)
上述代码实现了一种排序算法,可以将 a 数组按照从小到大的顺序排序。()
正确答案错误
解析详情
每层按 `a[i] > mid` 分组:较大的数从区间左端写入,较小或相等的数从右端写入;递归又先处理较大值域。因此最终顺序是从大到小,不是从小到大。
第 17 题(判断题,2 分)
如果在程序开始之前向 b 数组里写入数据(保证不会发生数组越界),则上述代码的输出不会发生变化。()
正确答案正确
解析详情
每次处理区间 时,循环恰好给 `b[p..q]` 的每个位置赋一次新值,随后才复制回 `a[p..q]`。因此递归过程中不会读取预先存入 `b` 的旧数据,输出不受影响。
第 18 题(判断题,2 分)
若 n = m,存在某种数据构造方式,使得上述代码运行的时间复杂度为 ,这是因为算法本身是对快速排序的改进,但是这种改进不能避免由于对数组的划分不够均等而在极端数据下导致复杂度发生退化。()
正确答案错误
解析详情
递归划分的是值域 ,每次都在中点处分成两半,深度固定为 ,不会因数据分组不均而退化成线性深度。 时每个元素至多参与每层一次扫描,总复杂度为 。
第 19 题(判断题,2 分)
如果将 ① 处的 `l >= r` 条件删除(同时删除 `||` 使程序能够正常编译,下同),程序的时间复杂度不会发生变化;而将 `p > q` 条件删除,程序在某些数据下的运行效率将会明显降低。( )
正确答案错误
解析详情
若删除 `l >= r`,当值域缩到单点且仍有元素时,`very_quick_sort(l,l,p,q)` 会再次递归到同一非空状态,可能无限递归。删除 `p > q` 则会继续展开空数据区间直到值域单点,确会增加无效调用;前半句已经错误。
第 20 题(单选题,3 分)
不认为 n, m 同阶,即可能出现 n 远大于 m 或者 m 远大于 n 的情况。则该程序的最坏时间复杂度为()。
正确答案D
解析详情
值域 每次折半,递归深度为 ;同一层的非空数据区间互不重叠,总扫描量为 。因此最坏总时间为 。
第 21 题(单选题,3 分)
若输入数据为:
10 10 10 4 5 2 2 3 1 5 8 3
那么在程序执行到 ② 位置时, b 数组内的值为()。
正确答案C
解析详情
第一次按 `mid=5` 分组后,10、8 位于左段,其余元素反向写入右段;后续递归继续按值域二分。所有递归完成时,`a` 与各段最后写入的 `b` 都按降序排列,所以 `b[1..10]` 为 `[10,8,5,5,4,3,3,2,2,1]`。
二、阅读程序(2)
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
const int mod = 1000000000 + 7;
int w0[100005];
int w1[100005];
int w2[100005];
int n, m, k, f[100005], d[100005], id[100005];
vector<int> e[100005];
void dfs(int u, int fa) {
d[u] = d[fa] + 1;
f[u] = fa;
for (auto &v : e[u]) if (v != fa) {
dfs(v, u);
}
}
bool cmp(int a, int b) {
return d[a] < d[b];
}
int main() {
cin >> n >> m >> k;
for (int i = 2; i <= n; i++) {
int u, v;
cin >> u >> v;
e[u].push_back(v);
e[v].push_back(u);
}
dfs(1, 0); // ①
for (int i = 1; i <= m; i++) {
int x, w;
cin >> x >> w;
w1[x] = (w1[x] + w) % mod;
w2[x] = (w2[x] + w) % mod;
}
for (int i = 1; i <= n; i++)
id[i] = i;
sort(id + 1, id + 1 + n, cmp);
for (int i = 1; i <= k; i++) {
for (int j = n; j >= 1; j--) {
int x = id[j];
for (auto &y : e[x]) if (y != f[x]) {
w1[y] = (w1[y] + w1[x]) % mod;
}
w1[x] = 0;
}
for (int x = 1; x <= n; x++)
w1[x] = (w1[x] - w0[x] + mod) % mod,
w0[x] = 0;
for (int j = 1; j <= n; j++) { // ②
int x = id[j];
if (f[x]) {
w1[f[x]] = (w1[f[x]] + w2[x]) % mod;
w2[f[x]] = (w2[f[x]] + w2[x]) % mod;
w0[x] = (w0[x] + w2[x]) % mod;
w2[x] = 0;
}
}
}
for (int i = 1; i <= n; i++)
cout << w1[i] << " ";
return 0;
}第 22 题(判断题,2 分)
如果更改 ① 处 `dfs(1, 0)` 为 `dfs(n, 0)`,则输出结果可能有变化。( )
正确答案错误
解析详情
第一重循环把每个点的 `w1` 向其孩子移动一层,第二重循环再把 `w2` 向父亲移动一层,并用 `w0` 消去立即折返的贡献。每轮最终得到与源点距离恰好多 1 的权值和,这一结果只由无根树距离决定,改以节点 为根不会改变输出。
第 23 题(判断题,1 分)
如果 ,那么输出结果均为 0。( )
正确答案正确
解析详情
含 个节点的树中任意两点距离至多为 。程序进行 轮后保留的是距离恰为 的源权值;当 时不存在这样的点对,所以所有输出均为 0。
第 24 题(判断题,2 分)
如果更改 ② 处 for(int j=1;j<=n;j++) 为 for(int j=n;j>=1;j--),那么对于任意合法的输入数据,更改前后程序的输出均相同。()
正确答案错误
解析详情
原循环按深度从浅到深处理,使一个节点本轮的 `w2` 只上移一条边;若改为从深到浅,子节点传来的值会在同一轮继续经父节点上移,可能一次跨越多条边。传播距离改变,输出不可能对所有输入都相同。
第 25 题(单选题,2 分)
该程序的时间复杂度为()。
正确答案B
解析详情
建树和每轮两次遍历都只对每个点、每条边做常数次操作,因此 轮主体为 ;读入 个初始权值为 ,对应选项 B。严格按当前 `std::sort` 实现还存在一次 的预处理,但可用 DFS 顺序线性得到同样的深度序。
第 26 题(单选题,3 分)
对于以下输入数据,输出结果为( )。
5 2 1
1 2
2 3
3 4
3 5
1 5
3 2正确答案A
解析详情
只有节点 1 的权值 5 和节点 3 的权值 2 非零,且 。每个点输出其相邻点的源权值和:节点 2 得 ,节点 4、5 各得 2,节点 1、3 得 0,因此输出 `0 7 0 2 2`。
第 27 题(单选题,3 分)
对于以下输入数据,输出结果为( )。
9 9 2
1 2
1 7
2 3
2 4
7 8
4 5
4 6
8 9
1 1
2 10
3 100
4 1000
5 10000
6 100000
7 1000000
8 10000000
9 100000000正确答案A
解析详情
两轮后,节点 的答案是所有与 距离恰为 2 的初始权值之和。例如节点 1 汇总节点 3、4、8,得 ;节点 2 汇总节点 5、6、7,得 1110000。逐点同算得到选项 A 的整行输出。
二、阅读程序(3)
#include <iostream>
using namespace std;
typedef long long i64;
namespace CirnoTree {
const int SIZ = 4e6 + 3;
int build1(int l, int r);
int build2(int l, int r);
int siz = 0;
int lft[SIZ], rgt[SIZ];
int nex[SIZ], son[SIZ];
i64 sum[SIZ];
i64 below_tag[SIZ];
i64 right_tag[SIZ];
int build1(int l, int r) {
int u = ++siz;
lft[u] = l;
rgt[u] = r;
son[u] = l == r ? 0 : build2(l, r);
return u;
}
int build2(int l, int r) {
int mid = (l + r) / 2;
int p = build1(l, mid);
nex[p] = l == r ? 0 : build2(mid + 1, r);
return p;
}
void update(int t) {
if (below_tag[t] != 0 && son[t] != 0) {
sum[son[t]] +=
1ll * (rgt[son[t]] - lft[son[t]] + 1) * below_tag[t];
below_tag[son[t]] += below_tag[t];
right_tag[son[t]] += below_tag[t];
}
below_tag[t] = 0;
if (right_tag[t] != 0 && nex[t] != 0) {
sum[nex[t]] +=
1ll * (rgt[nex[t]] - lft[nex[t]] + 1) * right_tag[t];
below_tag[nex[t]] += right_tag[t];
right_tag[nex[t]] += right_tag[t];
}
right_tag[t] = 0;
}
void modify(int t, int pos, int w) {
if (rgt[t] <= pos) {
below_tag[t] += w;
sum[t] += 1ll * w * (rgt[t] - lft[t] + 1);
} else {
int l = max(lft[t], 1);
int r = min(rgt[t], pos);
update(t);
sum[t] += 1ll * (r - l + 1) * w;
for (int p = son[t]; p != 0 && lft[p] <= pos; p = nex[p])
update(p), modify(p, pos, w);
}
}
i64 query(int t, int pos) {
if (rgt[t] <= pos) {
return sum[t];
} else {
update(t); i64 ans = 0;
for (int p = son[t]; p != 0 && lft[p] <= pos; p = nex[p])
update(p), ans += query(p, pos);
return ans;
}
}
};
int main() {
int n, m, root;
cin >> n >> m;
root = CirnoTree::build1(1, n);
for (int i = 1, x; i <= n; i++) {
cin >> x;
CirnoTree::modify(root, i, x);
}
for (int i = 1, op; i <= m; i++) {
cin >> op;
if (op == 1) {
int l, r, w;
cin >> l >> r >> w;
CirnoTree::modify(root, r, w);
CirnoTree::modify(root, l - 1, -w);
} else {
int l, r;
cin >> l >> r;
i64 w1 = CirnoTree::query(root, r);
i64 w2 = CirnoTree::query(root, l - 1);
cout << w1 - w2 << endl;
}
}
return 0;
}第 28 题(判断题,2 分)
该程序的功能如下文所述:( )
读入数组 ,并执行 次操作:
- `1 l r w`:将 分别加上 ; - `2 l r`:计算 的值并输出。
正确答案错误
解析详情
`modify(root,pos,w)` 给内部序列的前缀 加 ,`query(root,pos)` 求该序列的前缀和。初始化时依次执行 `modify(root,i,a_i)`,所以内部第 项实际为后缀和 ;后续操作和查询针对的是这个变换后的序列,而不是题目所述的原数组。
第 29 题(判断题,2 分)
如果将主函数中的 `root = CirnoTree::build1(1, n);` 修改为 `root = CirnoTree::build2(1, 3 * n);`,则程序对任意合法输入的输出都不会改变。( )
正确答案正确
解析详情
`build2(1,3n)` 返回的第一个块是 `build1(1,\lfloor(3n+1)/2\rfloor)`,其右端至少为 ,已覆盖所有合法下标 。其后的兄弟块虽不会从 `root` 访问,但合法的 `modify/query` 也不会用到它们,因此输出不变。
第 30 题(判断题,2 分)
如果在 build 操作以后,执行函数片段 CirnoTree::query(root, -142857),程序会因为发生数组越界而非正常退出。()
正确答案错误
解析详情
调用 `query(root,-142857)` 时,根节点不满足 `rgt[t] <= pos`,随后遍历孩子的条件 `lft[p] <= pos` 从第一个孩子起就为假。函数直接返回 0,不会用负数作为数组下标,因此不会越界退出。
第 31 题(单选题,2 分)
当读入的n充分大时,CirnoTree的大小(即在主程序执行完build操作后变量siz的值)大约为()。
正确答案D
解析详情
设区间长度为 。`build2` 把右侧链的各块交给 `build1`,而每个非叶 `build1` 再增加一个根;由递推可得 ,且对 有 ,故 ,一般大规模 也约为 。
第 32 题(单选题,3 分)
对于该数据结构,调用一次 build 函数的最好时间复杂度为( );调用一次 modify 或 query 函数的最坏时间复杂度为( )。
正确答案A
解析详情
构造过程为每个生成的节点做常数工作,而节点总数为 ,所以一次 build 为 。前缀可被该递归结构分解为每层至多常数个有效块,层数为 ,故 modify 和 query 的最坏时间均为 。
第 33 题(单选题,3 分)
对于以下输入,在程序执行到 `return 0` 之前,`below_tag[8]` 和 `right_tag[8]` 的值分别是( )。
8 3
0 0 0 0 0 0 0 0
1 1 8 3
1 2 6 2
2 5 8正确答案A
解析详情
节点 8 对应区间 。第一次给 加 3 后,根标记在下一次部分修改时下传;访问节点 8 前执行 `update(8)`,把其中的 3 继续推给子、右链并将自身两标记清零。随后 加 2 完全覆盖节点 8,只留下 `below_tag[8]=2`;之后查询不会再下传它,故 `right_tag[8]=0`。
三、完善程序(1)
(1)(异或和)给定序列 ,求其所有子区间异或和的和。某个区间的异或和的意思是将这个区间内的所有数字分别进行异或计算。其中 , 。
提示:对每一位独立计算,对右端点扫描线,并用异或前缀和辅助统计。
试补全程序。
#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 7;
int n, a[N], cnt[2];
long long ans;
int main() {
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i], ①;
for (int bit = ②; ③; bit--) {
cnt[0] = cnt[1] = 0;
for (int i = 0; i <= n; i++) {
cnt[④]++;
ans += 1LL * ⑤;
}
}
cout << ans;
}第 34 题(单选题,3 分)
① 处应填( )。
a[i - 1] ^= a[i]a[i] ^= a[i - 1]a[i - 1] += a[i]a[i] += a[i - 1]正确答案B
解析详情
令 `a[i]` 保存前缀异或,则应满足 。读入原值后执行 `a[i] ^= a[i-1]` 正好完成这一递推,之后区间异或可由两个前缀异或得到。
第 35 题(单选题,3 分)
② 处应填()。
n - 129nn + 1正确答案B
解析详情
因为 ,可能出现的最高二进制位编号是 29。循环应从 `bit=29` 向第 0 位枚举。
第 36 题(单选题,3 分)
③ 处应填( )。
bitbit >= nbit - 1~bit正确答案D
解析详情
循环变量从 29 递减,希望在处理 `bit=0` 后停止。对非负 `bit`,`~bit` 非零;当 `bit` 递减为 时,`~(-1)=0`,循环恰好结束,因此应填 `~bit`。
第 37 题(单选题,3 分)
④ 处应填( )。
(a[i] >> bit) & 1a[i] & (1 << bit)a[i] & (1LL << bit)(a[i] >> bit) ^ 1正确答案A
解析详情
`cnt` 只有下标 0、1,必须提取前缀异或 `a[i]` 的第 `bit` 位,即 `(a[i] >> bit) & 1`。B、C 得到的是 0 或 ,不能直接作为 `cnt` 下标。
第 38 题(单选题,3 分)
⑤ 处应填( )。
cnt[(a[i] >> bit) & 1] << icnt[(a[i] >> bit) & 1^1] << bitcnt[(a[i] >> bit) & 1] << bitcnt[(a[i] >> bit) & 1^1] << i正确答案B
解析详情
当前前缀第 `bit` 位为 时,只有此前第该位为 的前缀与它组成的区间异或位为 1,共 `cnt[v^1]` 个。每个这样的区间贡献 ,所以累加 `cnt[((a[i] >> bit) & 1) ^ 1] << bit`。
三、完善程序(2)
(2)(覆盖)给定序列(,),描述个格子的状态。若为,则表示覆不覆盖均可;若为,则表示一定不能覆盖;若为,则表示一定要被覆盖。询问依次进行次操作(),每次选定一个区间的格子将其覆盖,使得满足数组的所有限制条件,有多少种方案?两种方案不同,当且仅当存在某次操作覆盖的区间不同。如果格子可以被覆盖,则可以被覆盖多次。
如图例(第一张图和第四张图算不同方案,因为步骤1覆盖的区间不同。):
提示:考虑容斥原理,使用动态规划求出每种权值的贡献次数。
试补全程序。
#include <iostream>
using namespace std;
const int MAXN = 100 + 3;
const int MAXM = 1e4 + 3;
const int MOD = 1e9 + 7;
int F[2][MAXN][MAXM], A[MAXN];
int power(int a, int b) {
int r = 1;
while (b) {
if (b & 1) r = 1ll * r * a % MOD;
b >>= 1, ①;
}
return r;
}
int main() {
int n, m;
cin >> n >> m;
int h = n * (n + 1) / 2;
for (int i = 1; i <= n; i++)
cin >> A[i];
②;
F[0][0][0] = 1;
for (int i = 1; i <= n + 1; i++)
if (A[i] == 1 || A[i] == 2) {
for (int j = i - 1; j >= 0; j--) {
int c = ③;
int g = ④;
for (int k = h; k >= g; --k) {
F[0][i][k] = (F[0][i][k] + F[0 ^ c][j][k - g]) % MOD;
F[1][i][k] = (F[1][i][k] + F[1 ^ c][j][k - g]) % MOD;
}
if (A[j] == 1) break;
}
}
int ans = 0;
for (int i = 0; i <= h; i++) {
ans = (ans + 1ll * F[0][n + 1][i] * power(i, m)) % MOD;
ans = (ans + 1ll * ⑤ * power(i, m)) % MOD;
}
cout << ans << endl;
return 0;
}第 39 题(单选题,3 分)
① 处应填( )。
r = 1ll * r * r % MODa = 1ll * a * a % MODr = 1ll * r * a % MODa = 1ll * r * a % MOD正确答案B
解析详情
二进制快速幂每轮把指数 `b` 右移一位,同时必须把底数平方,使下一位对应 。因此逗号后的语句应为 `a = 1ll * a * a % MOD`。
第 40 题(单选题,3 分)
② 处应填()。
A[0] = 1, A[n + 1] = 1A[0] = 1, A[n + 1] = 2A[0] = 2, A[n + 1] = 1A[0] = 2, A[n + 1] = 2正确答案A
解析详情
DP 按不能跨越的关键位置切分区间,需要在序列左右两端各放一个“不可覆盖”哨兵,才能统一处理首段和尾段并在 `n+1` 汇总答案。因此设置 `A[0]=1, A[n+1]=1`。
第 41 题(单选题,3 分)
③ 对应填( )。
(A[i] == 2) ^ (A[j] == 2)A[j] == 2A[i] == 2(A[i] == 2) ^ (A[j] == 2)正确答案C
解析详情
`F[0]`、`F[1]` 分别累计容斥集合大小为偶数、奇数的贡献。转移选择当前关键点 时,只有 `A[i]==2` 表示把一个“必须覆盖”点加入容斥集合,需要翻转奇偶层,所以 `c = (A[i] == 2)`。原比赛曾勘误 A 选项,但不影响 C 的结论。
第 42 题(单选题,3 分)
④ 处应填()。
!(i - j) * (i - j + 1)(i - j) * (i - j + 1) / 2(i - j - 1) * (i - j) / 2(i - j) * (i - j)正确答案B
解析详情
相邻关键位置为 时,按该 DP 的边界约定可选连续区间长度为 ;长度为 的连续段共有 个子区间。因此 `g=(i-j)*(i-j+1)/2`。
第 43 题(单选题,3 分)
⑤ 处应填( )。
(F[1][n + 1][i] - 1 + MOD)F[0][n + 1][i](MOD - F[1][n + 1][i])(MOD - F[0][n + 1][i])正确答案C
解析详情
容斥中偶数个限制集合的贡献取正,奇数个限制集合的贡献取负,因此答案为 。模 `MOD` 下负的 `F[1]` 应写成 `MOD - F[1][n+1][i]`,对应 C。