本文使用 AI 辅助整理生成,相关信息来源网络。
注:完善程序第一题存在原题
- https://qoj.ac/problem/10692/statement/zh_cn?locale=zh-cn
- https://codeforces.com/contest/1622/problem/E
题目
一、单项选择题(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)
- 执行下列代码后,
cnt的值是( )
cpp
int x = 2026, cnt = 0;
while (x) {
x &= x - 1;
cnt++;
}
A. 6
B. 7
C. 11
D. 8
-
用权值 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } \{1, 2, 3, 4, 5, 6, 7, 8\} {1,2,3,4,5,6,7,8} 构造哈夫曼树,其带权路径长度是( )
A. 108
B. 96
C. 99
D. 102
-
把 1 到 1000 的所有整数按十进制写出,数字"1"总共出现了多少次( )
A. 300
B. 271
C. 301
D. 320
-
将 5 封信随机装入 5 个写好地址的信封(每封一个),恰好有 2 封装对的方案数是( )
A. 44
B. 24
C. 10
D. 20
-
3 2026 m o d 100 3^{2026} \bmod 100 32026mod100 的值是( )
A. 29
B. 9
C. 43
D. 81
-
有 5 堆石子排成一行,重量依次为 4 , 1 , 3 , 2 , 5 4, 1, 3, 2, 5 4,1,3,2,5。每次只能把相邻的两堆合并成一堆,代价为这两堆重量之和。将所有石子合并成一堆的最小总代价是( )
A. 36
B. 35
C. 34
D. 33
-
树状数组维护长度 n = 16 n = 16 n=16 的序列。查询前缀和 s u m ( 11 ) \mathrm{sum}(11) sum(11) 与单点修改 a d d ( 3 , x ) \mathrm{add}(3, x) add(3,x) 分别需要访问树状数组中多少个下标( )
A. 3 和 4
B. 4 和 4
C. 3 和 5
D. 4 和 3
-
有向无环图 G G G 顶点集为 { 1 , 2 , 3 , 4 } \{1, 2, 3, 4\} {1,2,3,4},边集为 { ( 1 , 2 ) , ( 1 , 3 ) } \{(1, 2), (1, 3)\} {(1,2),(1,3)},顶点 4 与任何顶点均不相邻。该图不同的拓扑序共有多少种( )
A. 12
B. 8
C. 4
D. 6
-
某分治算法满足 T ( n ) = T ( n / 3 ) + T ( 2 n / 3 ) + Θ ( n ) T(n) = T(n/3) + T(2n/3) + \Theta(n) T(n)=T(n/3)+T(2n/3)+Θ(n), T ( 1 ) = O ( 1 ) T(1) = O(1) T(1)=O(1),则 T ( n ) T(n) T(n) 是( )
A. Θ ( n log n ) \Theta(n \log n) Θ(nlogn)
B. Θ ( n 2 ) \Theta(n^2) Θ(n2)
C. Θ ( n 1.5 ) \Theta(n^{1.5}) Θ(n1.5)
D. Θ ( n ) \Theta(n) Θ(n)
-
无根树含 9 个结点(编号为 1---9),边集为 { ( 1 , 2 ) , ( 1 , 3 ) , ( 2 , 4 ) , ( 2 , 5 ) , ( 3 , 6 ) , ( 6 , 7 ) , ( 7 , 8 ) , ( 5 , 9 ) } \{(1,2), (1,3), (2,4), (2,5), (3,6), (6,7), (7,8), (5,9)\} {(1,2),(1,3),(2,4),(2,5),(3,6),(6,7),(7,8),(5,9)}。该树的直径(以边数计)与重心分别是( )
A. 直径 6,重心为结点 3
B. 直径 7,重心为结点 2
C. 直径 8,重心为结点 1
D. 直径 7,重心为结点 1
- 一张有向图缩点后得到的有向无环图含 6 个顶点,其中入度为 0 的顶点有 3 个、出度为 0 的顶点有 4 个。为使原图变成强连通图,至少需要添加多少条有向边( )
A. 7
B. 6
C. 4
D. 3
- 含 6 个结点的不同形态的二叉树共有多少棵(结点不带标号,区分左右子树)( )
A. 42
B. 429
C. 132
D. 720
- 字符串 S = "ababaabab" S = \text{"ababaabab"} S="ababaabab",其所有既是真前缀又是真后缀的子串(非空)的长度之和是( )
A. 4
B. 6
C. 7
D. 5
- 用归并排序统计逆序对,合并部分的核心代码为
cpp
// 归并 a[l..mid] 与 a[mid+1..r],同时累加逆序对
if (a[i] <= a[j]) {
tmp[k++] = a[i++]; // 取左半段元素
} else {
tmp[k++] = a[j++]; // 取右半段元素
ans += mid - i + 1;
}
若把判断条件中的 a[i] <= a[j] 改成 a[i] < a[j],则 ans 统计出的结果是( )
A. 完全不变
B. 变为原来的两倍
C. 变为满足 i < j i < j i<j 且 a i ≥ a j ai \ge aj ai≥aj 的数对个数
D. 变为原来的一半
- 执行
power(2, 100, 1000)调用下列函数,返回值是( )
cpp
long long power(long long a, long long b, long long p) {
long long r = 1 % p;
while (b) {
if (b & 1)
r = r * a % p;
a = a * a % p;
b >>= 1;
}
return r;
}
A. 576
B. 376
C. 976
D. 176
二、阅读程序(程序输入不超过数组或字符串定义的范围;判断题正确填 √,错误填 ×;除特殊说明外,判断题 1.5 分,选择题 3 分,共计 40 分。)
(1)
cpp
01 #include <iostream>
02 #include <string>
03 using namespace std;
04 int a[100];
05 string s;
06 int gen[13] = {1, 1, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1};
07 int main() {
08 cin >> s;
09 for (int i = 0; i < 32; ++i) {
10 a[i] = s[i] - '0';
11 }
12 for (int i = 32; i < 44; ++i) {
13 a[i] = 0;
14 }
15 for (int i = 0; i < 32; ++i) {
16 if (a[i] == 0) continue;
17 for (int j = 0; j < 13; ++j) {
18 a[i + j] ^= gen[j];
19 }
20 }
21 for (int i = 32; i < 44; ++i) {
22 cout << a[i];
23 }
24 cout << endl;
25 return 0;
26 }
(说明:输入保证为一个长度恰为 32 的 '0'/'1' 字符串。)
判断题
-
(1 分)当输入为 32 个
'0'时,程序输出 12 个 0。( ) -
程序运行结束后,数组
a中下标从 0 到 31 的元素一定全部为 0。( ) -
若将第 12~14 行(为
a[32]到a[43]补 0 的循环)删除,会改变程序输出结果。( )
单选题
- 关于第 6 行定义的数组
gen,下列说法正确的是( )。
A. gen 共有 12 个元素,表示一个 12 位的除数
B. gen 共有 13 个元素,表示一个 13 位的被除数
C. gen 共有 13 个元素,其中 gen[0] 是除数的最高位
D. gen 共有 13 个元素,其中 gen[12] 是除数的最高位
- 该程序实现的功能,最准确的说法是( )。
A. 将输入的 32 位串看成二进制数 M M M,输出 M M M 与 13 位二进制数 1100000001111 1100000001111 1100000001111 按位异或的结果
B. 将输入串视为 32 位二进制数 M M M,在其后补 12 个 0(即计算 M × 2 12 M \times 2^{12} M×212),再对它用 1100000001111 1100000001111 1100000001111 作模 2 除法求余数,并输出 12 位余数
C. 对输入的 32 位串逐位取反并输出结果
D. 统计输入串中 1 的个数,并把该个数用 12 位二进制表示后输出
- 若将第 16 行
if (a[i] == 0) continue;删除,说法正确的是( )。
A. 程序输出的结果不会改变
B. 可能造成程序运行错误
C. 程序能够正常输出一个 12 位 '0'/'1' 串,但是输出结果与输入的 s 无关
D. 程序运行结束后,a[0] 的值一定为 0
(2)
cpp
01 #include <iostream>
02 using namespace std;
03 int n, m, a[100007], L, R, lg[100007], i, j, t, dp[100007][25], pw[25];
04 int gcd(int x, int y) {
05 if (y == 0) return x;
06 return gcd(y, x % y);
07 }
08 int main() {
09 cin >> n >> m;
10 for (i = 1; i <= n; i++) cin >> a[i];
11 t = 0;
12 pw[0] = 1;
13 for (i = 1; i <= 24; i++) pw[i] = pw[i - 1] * 2;
14 for (i = 1; i <= 100000; i++)
15 if (pw[t + 1] > i) lg[i] = t;
16 else t++, lg[i] = t;
17 for (i = 1; i <= n; i++)
18 dp[i][0] = a[i];
19 for (j = 1; j <= lg[n]; j++)
20 for (i = 1; i + pw[j] - 1 <= n; i++) {
21 dp[i][j] = gcd(dp[i][j - 1], dp[i + pw[j - 1]][j - 1]);
22 }
23 for (i = 1; i <= m; i++) {
24 cin >> L >> R;
25 cout << gcd(dp[L][lg[R-L+1]], dp[R-pw[lg[R-L+1]]+1][lg[R-L+1]]) << endl;
26 }
27 return 0;
28 }
(说明:保证 1 ≤ n ≤ 100000 1 \le n \le 100000 1≤n≤100000,每次查询满足 1 ≤ L ≤ R ≤ n 1 \le L \le R \le n 1≤L≤R≤n,且数组 a 的元素均为正整数。)
判断题
-
当 n = 5 n = 5 n=5, a = { 4 , 2 , 6 , 3 , 9 } a = \{4, 2, 6, 3, 9\} a={4,2,6,3,9},且仅有一次查询 L = 2 L = 2 L=2、 R = 5 R = 5 R=5 时,输出为 1。( )
-
当某次查询的区间长度为 1(即 L = R L = R L=R)时,这次查询的输出一定等于
a[L]。( ) -
任意一次查询的输出结果一定不小于该查询区间内的最小值。( )
单选题
- 对于 j ≥ 1 j \ge 1 j≥1,数组
dp[i][j]保存的是( )。
A. 从 a[i] 开始连续 j j j 个数的最大公约数
B. 从 a[i] 开始连续 2 j 2^j 2j 个数的最大公约数
C. a[i] 与 a[j] 的最大公约数
D. 从 a[1] 到 a[i] 的最大公约数
- 若把一次求最大公约数的运算视为 O ( 1 ) O(1) O(1),则第 17~22 行建表过程的时间复杂度为( )。
A. Θ ( n ) \Theta(n) Θ(n)
B. Θ ( n log n ) \Theta(n \log n) Θ(nlogn)
C. Θ ( n 2 ) \Theta(n^2) Θ(n2)
D. Θ ( m n ) \Theta(mn) Θ(mn)
- 设 x x x 为一次查询的区间长度(即 x = R − L + 1 x = R - L + 1 x=R−L+1),则使得 l g x = 5 \mathrm{lg}x=5 lgx=5 的 x x x 的取值范围是( )。
A. 16 , 31 16, 31 16,31
B. 17 , 32 17, 32 17,32
C. 32 , 63 32, 63 32,63
D. 33 , 64 33, 64 33,64
(3)
cpp
01 #include <iostream>
02 using namespace std;
03 int n, fa[100007], f[100007], ans;
04 int main() {
05 cin >> n;
06 for (int i = 2; i <= n; ++i) {
07 cin >> fa[i];
08 }
09 for (int i = n; i >= 2; --i) {
10 if (f[fa[i]] + f[i] + 1 > ans) {
11 ans = f[fa[i]] + f[i] + 1;
12 }
13 if (f[i] + 1 > f[fa[i]]) {
14 f[fa[i]] = f[i] + 1;
15 }
16 }
17 cout << ans << endl;
18 return 0;
19 }
(说明:输入第一行为结点个数 n n n,第二行为 n − 1 n - 1 n−1 个整数,依次表示结点 2 ∼ n 2 \sim n 2∼n 的父结点编号,满足 2 ≤ n ≤ 100000 2 \le n \le 100000 2≤n≤100000 且 1 ≤ f a i < i 1 \le fai < i 1≤fai<i,根结点为 1。)
判断题
-
当 n = 5 n = 5 n=5, f a 2 ∼ f a 5 = { 1 , 2 , 3 , 4 } fa2 \sim fa5 = \{1, 2, 3, 4\} fa2∼fa5={1,2,3,4} 时,程序输出 4。( )
-
程序输出前,
f[1]的值一定等于ans的值。( ) -
将第 10~12 行与第 13~15 行两个
if语句的顺序交换后,程序的输出结果不受影响。( )
单选题
- 程序输出的
ans表示的是( )。
A. 树中距离最远的两个结点之间路径所经过的边数
B. 根结点 1 到最远叶子结点之间路径所经过的边数
C. 树中叶子结点的个数
D. 所有结点的父结点编号之和
- 当 n = 7 n = 7 n=7, f a 2 ∼ f a 7 = { 1 , 1 , 2 , 2 , 3 , 3 } fa2 \sim fa7 = \{1, 1, 2, 2, 3, 3\} fa2∼fa7={1,1,2,2,3,3} 时,输出为( )。
A. 2
B. 3
C. 4
D. 5
- 当 n = 10 n = 10 n=10,满足输出为 9 的合法输入种类数为( )。
A. 0
B. 9
C. 256
D. 512
三、完善程序(单选题,每小题 3 分,共计 30 分)
(1)(平衡路线)
给定一张有 n n n 个顶点、 m m m 条边的无向图,每条边带有符号 + 或 -。对于一条从顶点 s s s 到顶点 t t t 的路线,允许重复经过顶点和边,定义一条路线的权值如下:记 n + n_+ n+、 n − n_- n− 分别为经过的 + 边数和经过的 - 边数,则该路线的权值为 ∣ n + − n − ∣ |n_+ - n_-| ∣n+−n−∣。
请计算从 s s s 到 t t t 的路线的最小权值。若不存在从 s s s 到 t t t 的路线,则输出 − 1 -1 −1。
输入第一行为四个整数 n , m , s , t n, m, s, t n,m,s,t。接下来 m m m 行,每行给出两个整数 a , b a, b a,b 和一个字符 + 或 -,描述一条连接 a a a 与 b b b 的无向边及其符号。
数据满足 2 ≤ n ≤ 2 × 10 5 2 \le n \le 2 \times 10^5 2≤n≤2×105, 1 ≤ m ≤ 4 × 10 5 1 \le m \le 4 \times 10^5 1≤m≤4×105, 1 ≤ s , t ≤ n 1 \le s, t \le n 1≤s,t≤n 且 s ≠ t s \ne t s=t, 1 ≤ a , b ≤ n 1 \le a, b \le n 1≤a,b≤n,可能出现重边。
以下程序通过 BFS 求出最小权值。请补全程序。
cpp
01 #include <iostream>
02
03 constexpr int N = 200005;
04 constexpr int M = 400005;
05
06 int n, m, s, t;
07 int h[N], e[M << 1], ne[M << 1], w[M << 1], idx;
08 int q[N], d[N], c[N];
09
10 void add(int a, int b, int z) {
11 e[idx] = b;
12 w[idx] = z;
13 ne[idx] = h[a];
14 h[a] = idx++;
15 }
16
17 int main() {
18 std::cin >> n >> m >> s >> t;
19 for (int i = 1; i <= n; i++)
20 h[i] = d[i] = c[i] = -1;
21 for (int i = 0; i < m; i++) {
22 int a, b;
23 char op[2];
24 std::cin >> a >> b >> op;
25 int z = ① ;
26 add(a, b, z);
27 add(b, a, z);
28 }
29 int hh = 0, tt = 0;
30 int p = 0, ng = 0, ok = 1;
31 q[tt++] = s;
32 d[s] = c[s] = 0;
33 while ( ② ) {
34 int x = q[hh++];
35 for (int i = h[x]; i != -1; i = ne[i]) {
36 int y = e[i];
37 if (w[i] > 0) p = 1;
38 if (w[i] < 0) ng = 1;
39 if (d[y] == -1) {
40 d[y] = ③ ;
41 c[y] = c[x] ^ 1;
42 q[tt++] = y;
43 } else if ( ④ )
44 ok = 0;
45 }
46 }
47 if (d[t] == -1) {
48 std::cout << -1;
49 return 0;
50 }
51 if (!p || !ng) {
52 std::cout << d[t];
53 return 0;
54 }
55 if ( ⑤ ) std::cout << 0;
56 else std::cout << 1;
57 return 0;
58 }
- ①处应填( )
A. op[0] == '+' ? 0 : 1
B. op[0] == '+'
C. op[0] == '+' ? 1 : -1
D. op[0] == '-' ? 1 : 0
- ②处应填( )
A. hh < n
B. tt < n
C. hh <= tt
D. hh < tt
- ③处应填( )
A. d[y] + 1
B. d[x] + 1
C. d[x]
D. d[x] - 1
- ④处应填( )
A. c[y] == c[x]
B. w[i] == 1
C. c[y] != c[x]
D. d[y] + 1 != d[x]
- ⑤处应填( )
A. ok && c[s] == c[t]
B. ok && c[s] != c[t]
C. !ok || c[s] == c[t]
D. !ok && c[s] != c[t]
(2)(标准答案)
有 n n n 名学生参加一次考试,考试共有 m m m 道选择题,每道题只有 A、B 两个选项。第 i i i 名学生的作答用一个长度为 m m m 的字符串 a i a_i ai 表示。若最终公布的标准答案与该学生在某道题上的作答相同,则该学生得 1 分,否则不得分。记第 i i i 名学生最终得到的总分为 r i r_i ri。
给定每名学生的目标分数 x i x_i xi。现在需要构造一份标准答案,使 ∑ i = 1 n ∣ r i − x i ∣ \sum_{i=1}^{n} |r_i - x_i| ∑i=1n∣ri−xi∣ 尽可能大。
数据满足 1 ≤ n ≤ 20 1 \le n \le 20 1≤n≤20, 1 ≤ m ≤ 300 1 \le m \le 300 1≤m≤300, 0 ≤ x i ≤ m 0 \le x_i \le m 0≤xi≤m。
以下程序从枚举符号的角度处理 ∑ i = 1 n ∣ r i − x i ∣ \sum_{i=1}^{n} |r_i - x_i| ∑i=1n∣ri−xi∣,把它写成更易优化的形式。
对于非零整数 x x x,__builtin_ctzll(x) 返回 x x x 的二进制表示末尾连续 0 的个数。
__builtin_popcountll(x) 返回 x x x 的二进制表示中 1 的个数。
程序输出一组满足要求的标准答案。请补全程序。
cpp
01 #include <cstdlib>
02 #include <iostream>
03 #include <string>
04 #include <vector>
05
06 using namespace std;
07
08 typedef long long ll;
09 typedef unsigned long long ull;
10
11 int main() {
12 int n, m;
13 cin >> n >> m;
14 vector<ll> x(n), c(n);
15 for (int i = 0; i < n; i++) {
16 cin >> x[i];
17 c[i] = ① ;
18 }
19 vector<string> a(n);
20 for (int i = 0; i < n; i++)
21 cin >> a[i];
22
23 vector<int> s(n, -1);
24 vector<ll> q(m, 0);
25 ll C = 0, S = 0;
26 for (int i = 0; i < n; i++) {
27 C -= c[i];
28 for (int j = 0; j < m; j++) {
29 if (a[i][j] == 'A') q[j]--;
30 else q[j]++;
31 }
32 }
33 for (int j = 0; j < m; j++) S += abs(q[j]);
34 ll ans = C + S;
35 ull best = 0, lst = 0;
36
37 for (ull mask = 1; mask < (1ULL << n); mask++) {
38 ull g = ② ;
39 ull d = g ^ lst;
40 int k = ③ ;
41 C -= ④ ;
42 for (int j = 0; j < m; j++) {
43 ll old = q[j];
44 int v = (a[k][j] == 'A' ? 1 : -1);
45 q[j] -= 2ll * s[k] * v;
46 S += abs(q[j]) - abs(old);
47 }
48 s[k] = -s[k];
49 if (C + S > ans) {
50 ans = C + S;
51 best = g;
52 }
53 lst = g;
54 }
55
56 for (int i = 0; i < n; i++) {
57 if (best >> i & 1) s[i] = 1;
58 else s[i] = -1;
59 }
60
61 string res(m, 'A');
62 for (int j = 0; j < m; j++) {
63 ll v = 0;
64 for (int i = 0; i < n; i++) {
65 if (a[i][j] == 'A') v += s[i];
66 else v -= s[i];
67 }
68 if ( ⑤ ) res[j] = 'A';
69 else res[j] = 'B';
70 }
71 cout << res << endl;
72 return 0;
73 }
- ①处应填( )
A. 2 * x[i] - m
B. -m + 2 * x[i] + 1
C. m - 2 * x[i]
D. m + 2 * x[i]
- ②处应填( )
A. mask | (mask >> 1)
B. mask ^ (mask >> 1)
C. mask & (mask >> 1)
D. mask ^ ((mask >> 1) + 1)
- ③处应填( )
A. __builtin_ctzll(d) + 1
B. __builtin_popcountll(d)
C. __builtin_ctzll(g)
D. __builtin_ctzll(d)
- ④处应填( )
A. 2ll * s[k] * c[k]
B. s[k] * c[k]
C. 2ll * (s[k] - c[k])
D. 2ll * c[k]
- ⑤处应填( )
A. v >= (n & 1)
B. v > (n & 1)
C. v + (n & 1) >= 0
D. v * (n & 1) >= 0
答案详解
答案速查表
| 题号 | 答案 | 题号 | 答案 | 题号 | 答案 |
|---|---|---|---|---|---|
| 1 | D | 6 | C | 11 | C |
| 2 | D | 7 | A | 12 | C |
| 3 | C | 8 | B | 13 | B |
| 4 | D | 9 | A | 14 | C |
| 5 | A | 10 | D | 15 | B |
| 题号 | 答案 | 题号 | 答案 | 题号 | 答案 |
|---|---|---|---|---|---|
| 16 | √ | 22 | √ | 28 | √ |
| 17 | √ | 23 | √ | 29 | × |
| 18 | × | 24 | × | 30 | × |
| 19 | C | 25 | B | 31 | A |
| 20 | B | 26 | B | 32 | C |
| 21 | C | 27 | C | 33 | C |
| 题号 | 答案 | 填入内容 |
|---|---|---|
| 34 | C | op[0] == '+' ? 1 : -1 |
| 35 | D | hh < tt |
| 36 | B | d[x] + 1 |
| 37 | A | c[y] == c[x] |
| 38 | C | `!ok |
| 39 | A | 2 * x[i] - m |
| 40 | B | mask ^ (mask >> 1) |
| 41 | D | __builtin_ctzll(d) |
| 42 | A | 2ll * s[k] * c[k] |
| 43 | A | v >= (n & 1) |
一、单项选择题
第 1 题(答案 D)
x &= x - 1 每次消掉 x x x 二进制中最低位的 1,因此 cnt 就是 x x x 的二进制中 1 的个数。
2026 = 1024 + 512 + 256 + 128 + 64 + 32 + 8 + 2 = ( 11111101010 ) 2 2026 = 1024+512+256+128+64+32+8+2 = (11111101010)_2 2026=1024+512+256+128+64+32+8+2=(11111101010)2,含 8 个 1。
第 2 题(答案 D)
哈夫曼树带权路径长度等于所有合并代价之和 。权值 { 1 , 2 , 3 , 4 , 5 , 6 , 7 , 8 } \{1,2,3,4,5,6,7,8\} {1,2,3,4,5,6,7,8}:
| 步骤 | 合并 | 代价 | 剩余集合 |
|---|---|---|---|
| 1 | 1+2 | 3 | 3,3,4,5,6,7,8 |
| 2 | 3+3 | 6 | 4,5,6,6,7,8 |
| 3 | 4+5 | 9 | 6,6,7,8,9 |
| 4 | 6+6 | 12 | 7,8,9,12 |
| 5 | 7+8 | 15 | 9,12,15 |
| 6 | 9+12 | 21 | 15,21 |
| 7 | 15+21 | 36 | 36 |
总和 3 + 6 + 9 + 12 + 15 + 21 + 36 = 102 3+6+9+12+15+21+36 = 102 3+6+9+12+15+21+36=102。
第 3 题(答案 C)
把 1 ∼ 999 1\sim999 1∼999 写成三位数(补前导零,如 007 007 007),共 1000 1000 1000 个数。每一位上取到 1 的数的个数为 1000 / 10 = 100 1000/10 = 100 1000/10=100,三个数位共 300 300 300 个 1。
再加上 1000 1000 1000 贡献的 1 个 1,共 300 + 1 = 301 300 + 1 = 301 300+1=301。
第 4 题(答案 D)
先选出"装对的 2 封": ( 5 2 ) = 10 \binom{5}{2} = 10 (25)=10;
剩下 3 封必须全部装错,即 3 阶错排数 D 3 = 2 D_3 = 2 D3=2。
总数 10 × 2 = 20 10 \times 2 = 20 10×2=20。
第 5 题(答案 A)
3 3 3 模 100 100 100 的阶为 20 20 20( 3 10 = 59049 ≡ 49 3^{10}=59049\equiv 49 310=59049≡49, 49 2 = 2401 ≡ 1 ( m o d 100 ) 49^2 = 2401 \equiv 1 \pmod{100} 492=2401≡1(mod100))。
2026 m o d 20 = 6 2026 \bmod 20 = 6 2026mod20=6,所以
3 2026 ≡ 3 6 = 729 ≡ 29 ( m o d 100 ) 3^{2026} \equiv 3^{6} = 729 \equiv 29 \pmod{100} 32026≡36=729≡29(mod100)
第 6 题(答案 C)
这是环形/线性石子合并的区间 DP(注意:不是哈夫曼,因为只能合并相邻两堆)。
设 w = 4 , 1 , 3 , 2 , 5 w = 4,1,3,2,5 w=4,1,3,2,5,cost(l,r) 表示把 l ∼ r l\sim r l∼r 合并成一堆的最小代价:
| 区间 | 和 | 最优划分 | cost |
|---|---|---|---|
| (1,2) | 5 | --- | 5 |
| (2,3) | 4 | --- | 4 |
| (3,4) | 5 | --- | 5 |
| (4,5) | 7 | --- | 7 |
| (1,3) | 8 | (2,3) | 12 |
| (2,4) | 6 | (2,3) | 10 |
| (3,5) | 10 | (3,4) | 15 |
| (1,4) | 10 | min(10,10,12) | 20 |
| (2,5) | 11 | (2,4) | 21 |
| (1,5) | 15 | (1,3)+(4,5) | 15+19 = 34 |
最终答案是 34 34 34。
第 7 题(答案 A)
树状数组访问下标就是不断加上/减去 lowbit:
sum(11): 11 → 10 → 8 → 0 11 \to 10 \to 8 \to 0 11→10→8→0,访问 11 , 10 , 8 11, 10, 8 11,10,8 共 3 个;add(3, x): 3 → 4 → 8 → 16 → 32 3 \to 4 \to 8 \to 16 \to 32 3→4→8→16→32(超过 n n n 停止),访问 3 , 4 , 8 , 16 3,4,8,16 3,4,8,16 共 4 个。
第 8 题(答案 B)
1 1 1 必须在 2 2 2、 3 3 3 之前; 4 4 4 是孤立点,位置任意。
4 4 4 个顶点的全排列共 4 ! = 24 4! = 24 4!=24,其中" 1 1 1 排在 2 2 2、 3 3 3 之前"的占 1 / 3 1/3 1/3,所以 24 / 3 = 8 24/3 = 8 24/3=8。
第 9 题(答案 A)
T ( n ) = T ( n / 3 ) + T ( 2 n / 3 ) + Θ ( n ) T(n) = T(n/3) + T(2n/3) + \Theta(n) T(n)=T(n/3)+T(2n/3)+Θ(n)
两子问题规模之和为 n n n,每层划分代价为 Θ ( n ) \Theta(n) Θ(n),递归深度为 Θ ( log n ) \Theta(\log n) Θ(logn),所以 T ( n ) = Θ ( n log n ) T(n) = \Theta(n\log n) T(n)=Θ(nlogn)。
第 10 题(答案 D)
边集: 1 − 2 , 1 − 3 , 2 − 4 , 2 − 5 , 3 − 6 , 6 − 7 , 7 − 8 , 5 − 9 1{-}2, 1{-}3, 2{-}4, 2{-}5, 3{-}6, 6{-}7, 7{-}8, 5{-}9 1−2,1−3,2−4,2−5,3−6,6−7,7−8,5−9。
- 直径 :最长路径为 8 → 7 → 6 → 3 → 1 → 2 → 5 → 9 8\to7\to6\to3\to1\to2\to5\to9 8→7→6→3→1→2→5→9,共 7 条边。
- 重心 :删去结点 1 1 1 后得到的两个连通块大小分别为 { 2 , 4 , 5 , 9 } = 4 \{2,4,5,9\}=4 {2,4,5,9}=4 和 { 3 , 6 , 7 , 8 } = 4 \{3,6,7,8\}=4 {3,6,7,8}=4,都不超过 ⌊ 9 / 2 ⌋ = 4 \lfloor 9/2 \rfloor = 4 ⌊9/2⌋=4。而删去 2 2 2 会留下大小 5 5 5 的块,删去 3 3 3 同理。
所以重心是结点 1 1 1。
第 11 题(答案 C)
把缩点后的 DAG 变成强连通,需要添加的最少边数为
max ( 入度为 0 的点数 , 出度为 0 的点数 ) = max ( 3 , 4 ) = 4 \max(\text{入度为 0 的点数},\ \text{出度为 0 的点数}) = \max(3,4) = 4 max(入度为 0 的点数, 出度为 0 的点数)=max(3,4)=4
(前提是缩点后点数 ≥ 2 \ge 2 ≥2,本题为 6。)
第 12 题(答案 C)
含 n n n 个结点的不同形态二叉树数量为卡特兰数
C n = 1 n + 1 ( 2 n n ) , C 6 = 1 7 ( 12 6 ) = 132 C_n = \frac{1}{n+1}\binom{2n}{n},\qquad C_6 = \frac{1}{7}\binom{12}{6} = 132 Cn=n+11(n2n),C6=71(612)=132
第 13 题(答案 B)
S = "ababaabab" S = \text{"ababaabab"} S="ababaabab",逐长度检验"真前缀 = 真后缀":
| 长度 | 前缀 | 后缀 | 是否 |
|---|---|---|---|
| 8 | ababaaba | babaabab | ✗ |
| 7 | ababaab | abaabab | ✗ |
| 6 | ababaa | baabab | ✗ |
| 5 | ababa | aabab | ✗ |
| 4 | abab | abab | ✓ |
| 3 | aba | bab | ✗ |
| 2 | ab | ab | ✓ |
| 1 | a | b | ✗ |
真 border 长度为 4 , 2 4, 2 4,2,和 = 6 = 6 =6。
第 14 题(答案 C)
原代码 a[i] <= a[j] 走左半段,只有 a i > a j ai > aj ai>aj 才累加,统计的是严格逆序对 i < j , a i > a j i<j,\ ai > aj i<j, ai>aj。
改成 a[i] < a[j] 后,相等的情形也会走 else 分支并累加 mid - i + 1,于是相等对也被计入 ,统计的变成 i < j , a i ≥ a j i<j,\ ai \ge aj i<j, ai≥aj 的数对个数。
第 15 题(答案 B)
2 100 m o d 1000 2^{100} \bmod 1000 2100mod1000:从 2 10 = 1024 ≡ 24 2^{10} = 1024 \equiv 24 210=1024≡24 出发反复乘 24 24 24 取模,
2 20 ≡ 576 , 2 30 ≡ 824 , 2 40 ≡ 776 , 2 50 ≡ 624 , 2 60 ≡ 976 , 2 70 ≡ 424 , 2 80 ≡ 176 , 2 90 ≡ 224 , 2 100 ≡ 376 2^{20}\equiv 576,\ 2^{30}\equiv 824,\ 2^{40}\equiv 776,\ 2^{50}\equiv 624,\ 2^{60}\equiv 976,\ 2^{70}\equiv 424,\ 2^{80}\equiv 176,\ 2^{90}\equiv 224,\ 2^{100}\equiv 376 220≡576, 230≡824, 240≡776, 250≡624, 260≡976, 270≡424, 280≡176, 290≡224, 2100≡376
(验证: 2 100 = 1267650600228229401496703205376 2^{100} = 1267650600228229401496703205376 2100=1267650600228229401496703205376,末三位 376 376 376。)
二、阅读程序
程序(1):模 2 除法(CRC 校验)
gen = {1,1,0,0,0,0,0,0,0,1,1,1,1} 是一个 13 位 生成多项式(次数为 12),对应二进制串 1100000001111。
程序把输入的 32 位串看作二进制数 M M M,在末尾补 12 个 0(即 M × 2 12 M \times 2^{12} M×212),再做模 2 长除法,最后输出 12 位余数------这正是 CRC 校验的经典写法。
16. √
输入全 0 时每个 a[i] 都是 0,if (a[i] == 0) continue; 使得一次异或都不发生,a[32..43] 保持 0,输出 12 个 0。
17. √
处理下标 i i i 时:若 a[i] == 1,异或 gen(首位为 1)使 a[i] 归零;若 a[i] == 0 则跳过,它本来就是 0。而后续步骤 j > i j > i j>i 只会改动 a j . . j + 12 aj..j+12 aj..j+12,全部下标 ≥ j > i \ge j > i ≥j>i,不会再触碰 a i ai ai。因此最终 a[0..31] 全为 0。
18. ×
a 是全局数组 (定义在 main 之外),默认零初始化,a[32..43] 本来就已经是 0。删掉补 0 的循环不会改变任何结果。
19. C
gen 有 13 个元素,是模 2 除法的除数 ,其中 gen[0] = 1 是最高位。
20. B
选项 B 准确描述了"补 12 个零后作模 2 除法取 12 位余数"的 CRC 流程。
21. C
删掉 continue 后,无论输入是什么,程序都会在下标 0 ∼ 31 0\sim31 0∼31 上依次做固定的 32 次异或 。这些异或位置与输入无关,因此输出的是一个固定不移的 12 位 0/1 串(下标 31 + 12 = 43 < 100 31+12 = 43 < 100 31+12=43<100,不会越界),只是与 s 无关。
程序(2):ST 表求区间 gcd
dp[i][j] 表示从 a[i] 开始的 2 j 2^j 2j 个数的 gcd;查询时把区间拆成两个长度 2 k 2^{k} 2k( k = l g len k = \mathrm{lg}\\text{len} k=lglen)的重叠块再取 gcd。
22. √
L = 2 , R = 5 L=2, R=5 L=2,R=5: gcd ( 2 , 6 , 3 , 9 ) = gcd ( 2 , 6 ) = 2 → gcd ( 2 , 3 ) = 1 → gcd ( 1 , 9 ) = 1 \gcd(2,6,3,9) = \gcd(2,6)=2 \to \gcd(2,3)=1 \to \gcd(1,9)=1 gcd(2,6,3,9)=gcd(2,6)=2→gcd(2,3)=1→gcd(1,9)=1,输出 1。
23. √
长度 1 时 l g 1 = 0 \mathrm{lg}1 = 0 lg1=0,两个查询项都是 dp[L][0] = a[L], gcd ( a L , a L ) = a L \gcd(a_L, a_L) = a_L gcd(aL,aL)=aL。
24. ×
区间 gcd 一定能整除区间内每个元素,所以 gcd 不超过 区间最小值(例如区间 { 3 , 5 } \{3, 5\} {3,5} 的 gcd 为 1 < 3 1 < 3 1<3)。说"一定不小于最小值"是错的。
25. B
dp[i][j] 覆盖 2 j 2^j 2j 个连续元素。
26. B
j j j 从 1 1 1 到 lg n \lg n lgn,每层 i i i 遍历 O ( n ) O(n) O(n) 个位置,单次 gcd 视为 O ( 1 ) O(1) O(1),总复杂度 Θ ( n log n ) \Theta(n \log n) Θ(nlogn)。
27. C
l g x = 5 \mathrm{lg}x = 5 lgx=5 等价于 2 5 ≤ x < 2 6 2^5 \le x < 2^6 25≤x<26,即 x ∈ 32 , 63 x \in 32, 63 x∈32,63。
程序(3):树上直径 DP
f[v] 表示以 v v v 为根的子树中"往下最长的链"(边数)。倒序处理 i = n ∼ 2 i = n \sim 2 i=n∼2 时:
- 先用 f f a \[ i ] + f i + 1 ffa\[i] + fi + 1 ffa\[i]+fi+1 更新
ans------ 相当于把"经过 f a i fai fai 的两条最长的向下链"拼起来; - 再把 f i + 1 fi + 1 fi+1 合并进 f f a \[ i ] ffa\[i] ffa\[i]。
这正是求**树的直径(边数)**的标准做法。
28. √
f a 2..5 = { 1 , 2 , 3 , 4 } fa2..5 = \{1,2,3,4\} fa2..5={1,2,3,4} 是一条链 1 − 2 − 3 − 4 − 5 1{-}2{-}3{-}4{-}5 1−2−3−4−5,直径 = 4 = 4 =4 条边。手工模拟:ans 依次变为 1 , 2 , 3 , 4 1,2,3,4 1,2,3,4,输出 4。
29. ×
f[1] 是"从根往下的最长链",而 ans 是全局直径,两者不总相等。反例( n = 8 n=8 n=8):
- f a 2 = 1 , f a 3 = 2 , f a 4 = 3 , f a 5 = 4 fa2=1,\ fa3=2,\ fa4=3,\ fa5=4 fa2=1, fa3=2, fa4=3, fa5=4(根下一条长链,长度 4)
- f a 6 = 2 , f a 7 = 6 , f a 8 = 7 fa6=2,\ fa7=6,\ fa8=7 fa6=2, fa7=6, fa8=7(结点 2 另一条链,长度 3)
直径是 5 − 4 − 3 − 2 − 6 − 7 − 8 = 6 5{-}4{-}3{-}2{-}6{-}7{-}8 = 6 5−4−3−2−6−7−8=6 条边,而 f 1 = 4 f1 = 4 f1=4。两者不等。
30. ×
交换两个 if 后,ans 会在 f[fa[i]] 已被 f[i]+1 更新之后再计算,从而把同一条链重复计数。
反例(链 1 − 2 − 3 − 4 − 5 1{-}2{-}3{-}4{-}5 1−2−3−4−5):原程序输出 4 4 4;交换顺序后 ans 会变成 2 → 4 → 6 → 8 2 \to 4 \to 6 \to 8 2→4→6→8,最终输出 8 8 8。
31. A
ans 表示树中距离最远的两个结点之间路径的边数,即直径。
32. C
f a 2..7 = { 1 , 1 , 2 , 2 , 3 , 3 } fa2..7 = \{1,1,2,2,3,3\} fa2..7={1,1,2,2,3,3} 的树为: 1 1 1 的孩子是 2 , 3 2,3 2,3; 2 2 2 的孩子是 4 , 5 4,5 4,5; 3 3 3 的孩子是 6 , 7 6,7 6,7。
最长路径如 4 − 2 − 1 − 3 − 6 4{-}2{-}1{-}3{-}6 4−2−1−3−6,共 4 4 4 条边。程序输出 4。
33. C
输出为 9 意味着 10 个结点的树直径是 9,也即这棵树必须是一条链。
在约束 f a i < i fai < i fai<i 下:把结点 2 ∼ 10 2\sim10 2∼10 任意分成两个"从 1 出发的递增分支",则每个分支内部按编号递增连边即得一条合法链。两个分支有序时共有 2 9 2^{9} 29 种分配,而"两支互换"给出同一棵树,故需除以 2:
2 9 2 = 2 8 = 256 \frac{2^{9}}{2} = 2^{8} = 256 229=28=256
(可用小规模验证: n = 4 n=4 n=4 时为 2 2 = 4 2^{2}=4 22=4,手工枚举 fa[2],fa[3],fa[4] 的 6 种组合,恰有 4 种成链。)
三、完善程序
(1)平衡路线
思路:BFS 求 s → t s\to t s→t 的最短路。同时用 c[] 做二染色判断连通块的二分性(ok),用 p/ng 标记是否同时存在 +、- 两种边。
分类讨论:
- 到不了 t t t → 输出 − 1 -1 −1;
- 连通块里只有一种符号的边 → 任意路线的 ∣ n + − n − ∣ |n_+ - n_-| ∣n+−n−∣ 就是路线长度,取最短路 d t dt dt;
- 两种符号都有 → 可来回走边把差值以 ± 2 \pm 2 ±2 为步长调整:
- 若连通块非二分 (存在奇环)→ 可以凑出偶差值 → 答案为 0 0 0;
- 若连通块二分 → 所有 s → t s\to t s→t 路线长度同奇偶,差值奇偶 = c t = ct =ct。 c t = 0 ct=0 ct=0 时答案 0 0 0,否则为 1 1 1。
34. C:op[0] == '+' ? 1 : -1
后面用 if (w[i] > 0) / if (w[i] < 0) 判断符号,说明权值存的是 ± 1 \pm1 ±1。+ 边存 1 1 1,- 边存 − 1 -1 −1。
35. D:hh < tt
手写 BFS 队列,tt 是队尾(入队后加一),hh 是队头。hh < tt 表示队列非空。若写成 hh <= tt,队列空时还会多取一个未使用的元素。
36. B:d[x] + 1
最短路按层扩展,子结点距离等于父结点距离 + 1 +1 +1。
37. A:c[y] == c[x]
y y y 已访问且与 x x x 同色,说明这条边连接了同色点,存在奇环 → 图不是二分图 → ok = 0。
38. C:!ok || c[s] == c[t]
按上面的分类,答案为 0 0 0 的条件就是"非二分 或者 s , t s,t s,t 同色"。
(2)标准答案
把每道题的答案编码为 A j = ± 1 A_j = \pm1 Aj=±1(选 A 为 + 1 +1 +1,选 B 为 − 1 -1 −1),学生作答 u i j = ± 1 u_{ij} = \pm1 uij=±1(答 A 为 + 1 +1 +1,答 B 为 − 1 -1 −1)。则
r i = m + ∑ j u i j A j 2 ⟹ r i − x i = ∑ j u i j A j − ( 2 x i − m ) 2 r_i = \frac{m + \sum_j u_{ij}A_j}{2} \;\Longrightarrow\; r_i - x_i = \frac{\sum_j u_{ij}A_j - (2x_i - m)}{2} ri=2m+∑juijAj⟹ri−xi=2∑juijAj−(2xi−m)
记 c i = 2 x i − m c_i = 2x_i - m ci=2xi−m, y i = ∑ j u i j A j y_i = \sum_j u_{ij}A_j yi=∑juijAj,目标就是最大化
∑ i = 1 n ∣ r i − x i ∣ = 1 2 ∑ i = 1 n ∣ y i − c i ∣ \sum_{i=1}^{n}|r_i - x_i| = \frac12\sum_{i=1}^{n}|y_i - c_i| i=1∑n∣ri−xi∣=21i=1∑n∣yi−ci∣
利用 ∣ z ∣ = max s ∈ { ± 1 } s z |z| = \max_{s\in\{\pm1\}} sz ∣z∣=maxs∈{±1}sz,可把"外层最大化 + 绝对值"交换顺序:
max A ∑ i ∣ y i − c i ∣ = max s ∈ { ± 1 } n ∑ j ∣ q j ( s ) ∣ − ∑ i s i c i , q j ( s ) = ∑ i s i u i j \max_{A}\sum_i|y_i-c_i| = \max_{s\in\{\pm1\}^n}\Big\\sum_j\|q_j(s)\| - \\sum_i s_i c_i\\Big,\qquad q_j(s) = \sum_i s_i u_{ij} Amaxi∑∣yi−ci∣=s∈{±1}nmaxj∑∣qj(s)∣−i∑sici,qj(s)=i∑siuij
程序正是用 q[j] 维护 q j ( s ) q_j(s) qj(s)、用 S = Σ|q[j]|、用 C 维护 ∑ i s i c i \sum_i s_i c_i ∑isici,并通过格雷码 枚举所有 s s s,每次只翻转一个 s k s_k sk,从而 O ( 1 ) O(1) O(1) 更新 C、 O ( m ) O(m) O(m) 更新 q。
39. A:2 * x[i] - m
即 c i = 2 x i − m c_i = 2x_i - m ci=2xi−m(由上面的推导得到)。
40. B:mask ^ (mask >> 1)
这是格雷码 公式。相邻两个 mask 的格雷码只差一位,保证 d = g ^ lst 恰好只有 1 个二进制位是 1。
41. D:__builtin_ctzll(d)
翻转的那一位就是 d 中唯一的 1 所在位置,用 ctzll 取出其下标 k k k( d ≠ 0 d \ne 0 d=0,因为格雷码相邻项必不相同)。
42. A:2ll * s[k] * c[k]
s k s_k sk 由 s k s_k sk 变为 − s k -s_k −sk 时, C = ∑ i s i c i C = \sum_i s_i c_i C=∑isici 的变化量为 ( − s k − s k ) ⋅ c k = − 2 s k c k ( -s_k - s_k)\cdot c_k = -2 s_k c_k (−sk−sk)⋅ck=−2skck,所以写作 C -= 2ll * s[k] * c[k]。
43. A:v >= (n & 1)
v = Σ s_i u_{ij} 与 n n n 同奇偶:
- n n n 为奇数时 v v v 不可能为 0,取
'A'当且仅当 v > 0 v > 0 v>0,即 v ≥ 1 = ( n & 1 ) v \ge 1 = (n\&1) v≥1=(n&1); - n n n 为偶数时 v v v 可能为 0,此时选 A 或 B 等价,约定取
'A',即 v ≥ 0 = ( n & 1 ) v \ge 0 = (n\&1) v≥0=(n&1)。
两种情况都归约为 v >= (n & 1)。