(有原题)CSP-S2026第一轮试题(附答案解析、markdown源码)

本文使用 AI 辅助整理生成,相关信息来源网络。

注:完善程序第一题存在原题

题目

一、单项选择题(共 15 题,每题 2 分,共计 30 分;每题有且仅有一个正确选项)

  1. 执行下列代码后,cnt 的值是( )
cpp 复制代码
int x = 2026, cnt = 0;
while (x) {
    x &= x - 1;
    cnt++;
}

A. 6

B. 7

C. 11

D. 8

  1. 用权值 { 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

  2. 把 1 到 1000 的所有整数按十进制写出,数字"1"总共出现了多少次( )

    A. 300

    B. 271

    C. 301

    D. 320

  3. 将 5 封信随机装入 5 个写好地址的信封(每封一个),恰好有 2 封装对的方案数是( )

    A. 44

    B. 24

    C. 10

    D. 20

  4. 3 2026   m o d   100 3^{2026} \bmod 100 32026mod100 的值是( )

    A. 29

    B. 9

    C. 43

    D. 81

  5. 有 5 堆石子排成一行,重量依次为 4 , 1 , 3 , 2 , 5 4, 1, 3, 2, 5 4,1,3,2,5。每次只能把相邻的两堆合并成一堆,代价为这两堆重量之和。将所有石子合并成一堆的最小总代价是( )

    A. 36

    B. 35

    C. 34

    D. 33

  6. 树状数组维护长度 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

  7. 有向无环图 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

  8. 某分治算法满足 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. 无根树含 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

  1. 一张有向图缩点后得到的有向无环图含 6 个顶点,其中入度为 0 的顶点有 3 个、出度为 0 的顶点有 4 个。为使原图变成强连通图,至少需要添加多少条有向边( )

A. 7

B. 6

C. 4

D. 3

  1. 含 6 个结点的不同形态的二叉树共有多少棵(结点不带标号,区分左右子树)( )

A. 42

B. 429

C. 132

D. 720

  1. 字符串 S = "ababaabab" S = \text{"ababaabab"} S="ababaabab",其所有既是真前缀又是真后缀的子串(非空)的长度之和是( )

A. 4

B. 6

C. 7

D. 5

  1. 用归并排序统计逆序对,合并部分的核心代码为
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. 变为原来的一半

  1. 执行 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. (1 分)当输入为 32 个 '0' 时,程序输出 12 个 0。( )

  2. 程序运行结束后,数组 a 中下标从 0 到 31 的元素一定全部为 0。( )

  3. 若将第 12~14 行(为 a[32]a[43] 补 0 的循环)删除,会改变程序输出结果。( )

单选题

  1. 关于第 6 行定义的数组 gen,下列说法正确的是( )。

A. gen 共有 12 个元素,表示一个 12 位的除数

B. gen 共有 13 个元素,表示一个 13 位的被除数

C. gen 共有 13 个元素,其中 gen[0] 是除数的最高位

D. gen 共有 13 个元素,其中 gen[12] 是除数的最高位

  1. 该程序实现的功能,最准确的说法是( )。

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 位二进制表示后输出

  1. 若将第 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 的元素均为正整数。)

判断题

  1. 当 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。( )

  2. 当某次查询的区间长度为 1(即 L = R L = R L=R)时,这次查询的输出一定等于 a[L]。( )

  3. 任意一次查询的输出结果一定不小于该查询区间内的最小值。( )

单选题

  1. 对于 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] 的最大公约数

  1. 若把一次求最大公约数的运算视为 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)

  1. 设 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。)

判断题

  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。( )

  2. 程序输出前,f[1] 的值一定等于 ans 的值。( )

  3. 将第 10~12 行与第 13~15 行两个 if 语句的顺序交换后,程序的输出结果不受影响。( )

单选题

  1. 程序输出的 ans 表示的是( )。

A. 树中距离最远的两个结点之间路径所经过的边数

B. 根结点 1 到最远叶子结点之间路径所经过的边数

C. 树中叶子结点的个数

D. 所有结点的父结点编号之和

  1. 当 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

  1. 当 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  }
  1. ①处应填( )

A. op[0] == '+' ? 0 : 1

B. op[0] == '+'

C. op[0] == '+' ? 1 : -1

D. op[0] == '-' ? 1 : 0

  1. ②处应填( )

A. hh < n

B. tt < n

C. hh <= tt

D. hh < tt

  1. ③处应填( )

A. d[y] + 1

B. d[x] + 1

C. d[x]

D. d[x] - 1

  1. ④处应填( )

A. c[y] == c[x]

B. w[i] == 1

C. c[y] != c[x]

D. d[y] + 1 != d[x]

  1. ⑤处应填( )

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  }
  1. ①处应填( )

A. 2 * x[i] - m

B. -m + 2 * x[i] + 1

C. m - 2 * x[i]

D. m + 2 * x[i]

  1. ②处应填( )

A. mask | (mask >> 1)

B. mask ^ (mask >> 1)

C. mask & (mask >> 1)

D. mask ^ ((mask >> 1) + 1)

  1. ③处应填( )

A. __builtin_ctzll(d) + 1

B. __builtin_popcountll(d)

C. __builtin_ctzll(g)

D. __builtin_ctzll(d)

  1. ④处应填( )

A. 2ll * s[k] * c[k]

B. s[k] * c[k]

C. 2ll * (s[k] - c[k])

D. 2ll * c[k]

  1. ⑤处应填( )

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,5cost(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)

源码

https://gp3e.saobby.com/i/4SzDu7fqABnlfcVf.txt

相关推荐
m0_734571762 小时前
深入理解C++ RAII
开发语言·c++
hetao17338373 小时前
2026-09-18 hetao1733837 的刷题记录
c++·算法
stolentime3 小时前
CSP-J2026第一轮试题(附答案解析、markdown源码)
c++·csp
Rabitebla3 小时前
【Linux系统编程】 指令(二):一条路径是怎么定位到文件的
linux·c++·笔记·学习·算法
程序员老陆4 小时前
std::experimental::when_any 深度解析:等待“第一个完成”的异步组合原语
c++·多线程
Rabitebla4 小时前
【Linux系统编程】指令(三):创建、删除、复制、移动、看内容
linux·数据结构·c++·算法
程序员老陆5 小时前
CMake 常用关键字与命令全景:从 set到 target_link_options的现代工程视角
c++·cmake·程序开发
码匠许师傅5 小时前
【C++三方组件】cxxopts:轻量首选的命令行解析
c++
hansang_IR5 小时前
【讲解】CSP-S2026 第一轮初赛
c++·算法