🏠

🧪 CSP 初赛模拟考试 · 第二套模拟

选择题 15 题 + 阅读程序 3 段 + 完善程序 2 段 · 难度对齐 CSP-J 初赛 · 完整逐题精讲

📚 三大模块🎯 选择 30 分📖 阅读 + 完善 70 分⏱ 建议 120 分钟
← 返回主页
正在载入题库…

一、单项选择题(共 15 题,每题 2 分,共 30 分)

1. 易 以下哪一种设备属于输出设备:( )
A. 扫描仪 B. 键盘 C. 鼠标 D. 打印机
✅ 正确答案:D
解析:扫描仪、键盘、鼠标都把信息送入计算机,是输入设备;打印机把处理结果输出到纸张,是输出设备。
2. 易 如果 256 种颜色用二进制编码来表示,至少需要( )位。
A. 6 B. 7 C. 8 D. 9
✅ 正确答案:C
解析:n 位二进制可表示 2ⁿ 种状态。2⁸ = 256,所以至少需要 8 位。
3. 中 对于入栈顺序为 a, b, c, d, e 的序列,下列( )不是合法的出栈序列。
A. a, b, c, d, e B. e, d, c, b, a C. b, a, c, d, e D. c, d, a, e, b
✅ 正确答案:D
解析:D 项:要 c 第一个出栈,须压入 a、b、c 后弹出 c;再压入 d 弹出 d。此时栈顶是 b,下一个只能弹出 b,不可能弹出 a,故 D 不合法。
4. 中 如果一棵二叉树只有根结点,那么这棵二叉树高度为 1。请问高度为 5 的完全二叉树有( )种不同形态?
A. 16 B. 15 C. 17 D. 32
✅ 正确答案:A
解析:高度为 5 的完全二叉树,前 4 层必满(共 15 个结点),第 5 层结点数可以是 1 ~ 16 个中的任意一种,共 16 种形态。
5. 易 二进制数 11.01 在十进制下是( )。
A. 3.25 B. 4.125 C. 6.25 D. 11.125
✅ 正确答案:A
解析:11₂ = 3,.01₂ = 1/4 = 0.25,合起来 3.25。
6. 中 下列各无符号十进制整数中,能用八位二进制表示的数中最大的是( )。
A. 296 B. 133 C. 256 D. 199
✅ 正确答案:D
解析:8 位无符号数范围是 0 ~ 255。296、256 都超出范围;133 与 199 都能表示,最大的是 199。
7. 难 0、1、8 颠倒还是本身,6 颠倒成 9,9 颠倒成 6,其余数字颠倒不成数字。车牌由 5 位数字组成,则最多有多少个车牌倒过来恰好还是原来的车牌?( )
A. 60 B. 125 C. 75 D. 100
✅ 正确答案:C
解析:第 1 位与第 5 位颠倒后互换,只能取 {0,1,8,6,9} 中的 5 种(成对确定);第 2 位与第 4 位同理 5 种;第 3 位颠倒后仍是自己,只能取 {0,1,8} 共 3 种。
总数 = 5 × 5 × 3 = 75。
8. 易 二进制数 101.11 对应的十进制数是( )。
A. 6.5 B. 5.5 C. 5.75 D. 5.25
✅ 正确答案:C
解析:101₂ = 5,.11₂ = 1/2 + 1/4 = 0.75,合起来 5.75。
9. 中 每执行一次交换会减少 1 个逆序对,序列 5, 4, 3, 2, 1 需要执行( )次交换才能完成冒泡排序。
A. 0 B. 5 C. 10 D. 15
✅ 正确答案:C
解析:完全逆序的 5 个数,逆序对数为 4 + 3 + 2 + 1 = 10,每次交换消去 1 个,故需 10 次交换。
10. 中 由 1, 1, 2, 2, 3 这五个数字组成不同的三位数有( )种。
A. 18 B. 15 C. 12 D. 24
✅ 正确答案:A
解析:分类:三个数字都不同 {1,2,3} → 3! = 6 种;含两个 1(112/113/211/311/121/131)→ 6 种;含两个 2 → 6 种。合计 18 种。
11. 难 将(2, 6, 10, 17)存到地址区间为 0~10 的哈希表中,如果哈希函数 h(x) = ( ),将不会产生冲突。
A. x mod 11 B. x² mod 11 C. (2x) mod 11 D. ⌊√x⌋ mod 11
✅ 正确答案:D
解析:逐个代入四个关键字:
· A:2→2,6→6,10→10,17→6,6 与 10 冲突(17 mod 11 = 6,10 mod 11 = 10)✗
· B:2→4,6→3,10→1,17→3,3 冲突✗
· C:2→4,6→1,10→9,17→1,1 冲突✗
· D:⌊√2⌋=1、⌊√6⌋=2、⌊√10⌋=3、⌊√17⌋=4 → 1,2,3,4 全不重复 ✓
12. 易 寄存器是( )的重要组成部分。
A. 硬盘 B. 高速缓存 C. 内存 D. 中央处理器(CPU)
✅ 正确答案:D
解析:寄存器位于 CPU 内部,是速度最快的存储单元;硬盘是外存,内存与高速缓存在 CPU 之外。
13. 中 某算法的时间满足 T(n) = T(n − 1) + n(n 为正整数)且 T(0) = 1,则该算法的时间复杂度为( )。
A. O(log n) B. O(n log n) C. O(n) D. O(n²)
✅ 正确答案:D
解析:展开:T(n) = T(0) + 1 + 2 + … + n = 1 + n(n+1)/2 = O(n²)。
14. 易 100 以内最大的素数是( )。
A. 89 B. 97 C. 91 D. 93
✅ 正确答案:B
解析:97 是素数;91 = 7 × 13、93 = 3 × 31 都不是素数,故 100 以内最大素数为 97。
15. 难 下面的冒泡排序伪代码中,对 n 个数排序最少需要比较多少次?( )
FLAG ← n;while FLAG > 1 do:k ← FLAG − 1;FLAG ← 1;for j = 1 to k:if L(j) > L(j+1) 则交换且 FLAG ← j
A. n² B. n − 2 C. n − 1 D. n
✅ 正确答案:C
解析:最好情况(本来就有序):第一轮 k = n − 1,比较 n − 1 次,一次都没交换,FLAG 保持 1,while 立即结束。

二、阅读程序(第 16~18 题,含判断题与单选题)

阅读 1:Base64 解码(第 16 题)难

base[] 建立「下标 0~63 → 字符」的编码表,table[] 建立「字符 → 数码」的反查表。decode 每 4 个密文字符还原 3 个原文字符:6 bit × 4 = 8 bit × 3。= 是占位符,table['='] = 0。

C++程序代码(点击行号可定位)
  1. 01#include <stdio.h>
  2. 02#include <string.h>
  3. 03char base[64];
  4. 04char table[256];
  5. 05char str[256];
  6. 06char ans[256];
  7. 07
  8. 08void init() {
  9. 09 for (int i = 0; i < 26; i++) base[i] = 'A' + i;
  10. 10 for (int i = 0; i < 26; i++) base[26 + i] = 'a' + i;
  11. 11 for (int i = 0; i < 10; i++) base[52 + i] = '0' + i;
  12. 12 base[62] = '+';
  13. 13 base[63] = '/';
  14. 14 for (int i = 0; i < 256; i++) table[i] = 0xff;
  15. 15 for (int i = 0; i < 64; i++) table[base[i]] = i;
  16. 16 table['='] = 0;
  17. 17}
  18. 18
  19. 19void decode(char *str) {
  20. 20 char *ret = ans;
  21. 21 int i, len = strlen(str);
  22. 22 for (i = 0; i < len; i += 4) {
  23. 23 (*ret++) = table[str[i]] << 2 | table[str[i + 1]] >> 4;
  24. 24 if (str[i + 2] != '=')
  25. 25 (*ret++) = (table[str[i + 1]] & 0x0f) << 4 | table[str[i + 2]] >> 2;
  26. 26 if (str[i + 3] != '=')
  27. 27 (*ret++) = table[str[i + 2]] << 6 | table[str[i + 3]];
  28. 28 }
  29. 29}
  30. 30
  31. 31int main() {
  32. 32 init();
  33. 33 printf("%d\n", (int)table[0]);
  34. 34 scanf("%s", str);
  35. 35 decode(str);
  36. 36 printf("%s\n", ans);
  37. 37 return 0;
  38. 38}
▶ 输入样例
Y3Nx
▶ 输出样例
-1
csq
🪜 以输入 Y3Nx 为例还原第一个字符
1 L21 table 全部填 0xff(补码 11111111,即 −1),再对 64 个合法字符重新赋值
2 L30 首行输出 (int)table[0]:下标 0 从未被赋值,故为 0xff → 有符号 char 读作 −1
3 查表:table['Y'] = 24,table['3'] = 55,table['N'] = 13,table['x'] = 49
4 第 1 个字符:24 << 2 | 55 >> 4 = 011000 | 11 = 99 = 'c'
5 第 2 个字符:(55 & 0x0f) << 4 | 13 >> 2 = 0111 | 0011 = 115 = 's'
6 第 3 个字符:(13 & 0x03) << 6 | 49 = 01 | 110001 = 113 = 'q'
① 输出的第二行一定是由小写字母、大写字母、数字和 +、/、= 构成的字符串。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:第二行是解码后的原文,可以是任意字节(如空格、标点),并不限于 Base64 字符集。反例:Y2NmIDIwMjE= 解码后含空格。
② 可能存在输入不同,但输出的第二行相同的情形。
A. 正确 B. 错误
✅ 答案:A(正确)
解析:= 会让最后两个字符不参与还原,例如 a0== 与 al== 解码后同为 k;故不同输入可得到相同输出。
③ 输出的第一行为 "−1"。
A. 正确 B. 错误
✅ 答案:A(正确)
解析:table 初始化为 0xff,之后只给 64 个 Base64 字符与 '=' 赋值,下标 0 从未被赋值。char 为有符号类型,0xff 即 −1,故首行输出 −1。
④ 设输入字符串长度为 n,decode 函数的时间复杂度为( )。
A. O(√n) B. O(n) C. O(n log n) D. O(n²)
✅ 答案:B
解析:for 循环步长为 4,遍历整个字符串一次,循环体内是常数次位运算 → O(n)。
⑤ 当输入为 "Y3Nx" 时,输出的第二行为( )。
A. "csp" B. "csq" C. "CSP" D. "csP"
✅ 答案:B
解析:逐字符还原:99 = 'c',115 = 's',113 = 'q',得到 "csq"(这正是 CSP 的 Base64 变体写法)。
⑥ 当输入为 "Y2NmIDIwMjE=" 时,输出的第二行为( )。
A. "ccf2021" B. "ccf2022" C. "ccf 2021" D. "ccf 2022"
✅ 答案:C
解析:末尾有一个 =,最后 4 个字符只还原出 2 个原文字符,总长 3 + 3 + 2 = 8。分段解码:Y2Nm → "ccf",IDIwMjE= → " 2021",合起来 "ccf 2021"。

阅读 2:石子合并式 DFS 求最大值(第 17 题)难

d[i][0]、d[i][1] 是两组数。每次把相邻两行合并:s = a + x + |b − y|,dfs 枚举所有合并顺序取总和最大值(等价于区间 DP)。

C++程序代码(点击行号可定位)
  1. 01#include <algorithm>
  2. 02#include <iostream>
  3. 03using namespace std;
  4. 04
  5. 05int n;
  6. 06int d[50][2];
  7. 07int ans;
  8. 08
  9. 09void dfs(int n, int sum) {
  10. 10 if (n == 1) {
  11. 11 ans = max(sum, ans);
  12. 12 return;
  13. 13 }
  14. 14 for (int i = 1; i < n; ++i) {
  15. 15 int a = d[i - 1][0], b = d[i - 1][1];
  16. 16 int x = d[i][0], y = d[i][1];
  17. 17 d[i - 1][0] = a + x;
  18. 18 d[i - 1][1] = b + y;
  19. 19 for (int j = i; j < n - 1; ++j)
  20. 20 d[j][0] = d[j + 1][0], d[j][1] = d[j + 1][1];
  21. 21 int s = a + x + abs(b - y);
  22. 22 dfs(n - 1, sum + s);
  23. 23 for (int j = n - 1; j > i; --j)
  24. 24 d[j][0] = d[j - 1][0], d[j][1] = d[j - 1][1];
  25. 25 d[i - 1][0] = a, d[i - 1][1] = b;
  26. 26 d[i][0] = x, d[i][1] = y;
  27. 27 }
  28. 28}
  29. 29
  30. 30int main() {
  31. 31 cin >> n;
  32. 32 for (int i = 0; i < n; ++i)
  33. 33 cin >> d[i][0];
  34. 34 for (int i = 0; i < n; ++i)
  35. 35 cin >> d[i][1];
  36. 36 ans = 0;
  37. 37 dfs(n, 0);
  38. 38 cout << ans << endl;
  39. 39 return 0;
  40. 40}
▶ 输入样例
20
9 9 9 …(20 个 9)
0 0 0 …(20 个 0)
▶ 输出样例
1881
🪜 最优策略:每次都把「已合并的大块」与相邻块再合并
1 L15~L19 先把第 i−1 行与第 i 行相加,再把后面的行整体前移
2 L20~L21 本次得分 s = a + x + |b − y|,累加进 sum 后递归
3 L22~L25 回溯:把数组恢复成递归前的样子,保证其他分支正确
4 由于每次合并都让「累积块」越来越大,最优顺序就是一路往一端合并(毛毛虫形)
5 n 个 9、n 个 0:s₁ = 9+9+0 = 18,s₂ = 27,…,s₁₉ = 180
6 总和 = 18 + 27 + … + 180 = 9 × (2 + 3 + … + 20) = 9 × 209 = 1881
① 若输入 n 为 0,此程序可能会死循环或发生运行错误。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:n = 0 时 dfs(0, 0) 里 if (n == 1) 不成立,for (i = 1; i < 0; ++i) 一次也不执行,直接返回,输出 ans 初值 0。不会出错。
② 若输入 n 为 20,接下来的输入全为 0,则输出为 0。
A. 正确 B. 错误
✅ 答案:A(正确)
解析:所有数都是 0,每次合并 s = 0 + 0 + |0 − 0| = 0,sum 始终为 0,ans = max(0, 0) = 0。
③ 输出的数一定不小于输入的 d[i][0] 和 d[i][1] 中的任意一个。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:反例:n = 2,输入两行分别为 (1, 999) 与 (2, 998),唯一一次合并 s = 1 + 2 + |999 − 998| = 4,远小于 998、999。
④ n = 20,输入 20 个 9 和 20 个 0,输出为( )。
A. 1890 B. 1881 C. 1908 D. 1917
✅ 答案:B
解析:a、x 都是 9,b、y 都是 0,每次 s = 9k(k 为累积块大小)。最优顺序下 s = 18, 27, …, 180,总和 = 9 × (2 + 3 + … + 20) = 9 × 209 = 1881。
⑤ n = 30,输入 30 个 0 和 30 个 5,输出为( )。
A. 2000 B. 2010 C. 2030 D. 2020
✅ 答案:C
解析:a、x 恒为 0,s = |b − y|。累积块为 5k 时 s = |5k − 5| = 5(k − 1)。总和 = 0 + 5×1 + 5×2 + … + 5×28 = 5 × 406 = 2030。
⑥ n = 15,输入 15 到 1 以及 15 到 1,输出为( )。
A. 2440 B. 2220 C. 2240 D. 2420
✅ 答案:C
解析:两组完全相同 ⇒ |b − y| = 0,每次 s = a + x = 2 × 累积块。累积块依次为 15、29、42、…、119(共 14 项,和 1120),总和 = 2 × 1120 = 2240。

阅读 3:双数组贪心匹配(第 18 题)难

a[x] = y 表示「x 与 y 配对」。新来的 (x, y) 只有在 a[x] < y 且 b[y] < x 时才被接受:x 换更大的 y,y 换更小的 x,最终形成一条「x 递增、y 递减」的阶梯型匹配。

C++程序代码(点击行号可定位)
  1. 01#include<cstdio>
  2. 02using namespace std;
  3. 03int n, m;
  4. 04int a[100], b[100];
  5. 05
  6. 06int main() {
  7. 07 scanf("%d%d", &n, &m);
  8. 08 for (int i = 1; i <= n; ++i)
  9. 09 a[i] = b[i] = 0;
  10. 10 for (int i = 1; i <= m; ++i) {
  11. 11 int x, y;
  12. 12 scanf("%d%d", &x, &y);
  13. 13 if (a[x] < y && b[y] < x) {
  14. 14 if (a[x] > 0)
  15. 15 b[a[x]] = 0;
  16. 16 if (b[y] > 0)
  17. 17 a[b[y]] = 0;
  18. 18 a[x] = y;
  19. 19 b[y] = x;
  20. 20 }
  21. 21 }
  22. 22 int ans = 0;
  23. 23 for (int i = 1; i <= n; ++i) {
  24. 24 if (a[i] == 0)
  25. 25 ++ans;
  26. 26 if (b[i] == 0)
  27. 27 ++ans;
  28. 28 }
  29. 29 printf("%d", ans);
  30. 30 return 0;
  31. 31}
▶ 输入样例
5 3
1 3
2 2
3 1
▶ 输出样例
4
🪜 样例:n = 5,依次来 (1,3)、(2,2)、(3,1)
1 (1,3):a[1] = 0 < 3 且 b[3] = 0 < 1 → 接受,a[1] = 3, b[3] = 1
2 (2,2):a[2] = 0 < 2 且 b[2] = 0 < 2 → 接受,a[2] = 2, b[2] = 2
3 (3,1):a[3] = 0 < 1 且 b[1] = 0 < 3 → 接受,a[3] = 1, b[1] = 3
4 统计:a 中非零的有 a[1]、a[2]、a[3] → a 的 0 有 5 − 3 = 2 个
5 b 中非零的有 b[1]、b[2]、b[3] → b 的 0 有 2 个
6 输出 2 + 2 = 4,即 2n − 2 × 匹配数
① 当 m > 0 时,输出的值一定小于 2n。
A. 正确 B. 错误
✅ 答案:A(正确)
解析:第一对 (x, y) 必定被接受(a[x] = 0 < y,b[y] = 0 < x),所以匹配数 ≥ 1,输出 = 2n − 2 × 匹配数 ≤ 2n − 2 < 2n。
② 执行完第 27 行的 "++ans" 时,ans 一定是偶数。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:循环里对同一个 i 可能只加一次(a[i] == 0 但 b[i] ≠ 0,或反之),中途 ans 完全可以是奇数。反例:n = 2、匹配 (1,2),i = 1 时 a[1] = 2 ≠ 0、b[1] = 0 → ans = 1。
③ a[x] 和 b[y] 不可能同时大于 0。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:完全可能。例如已有匹配 (5,2)、(3,6),新来 (5,6) 时a[5] = 2 > 0 且 b[6] = 3 > 0 同时成立。
④ 若程序执行到第 13 行时,x 总是小于 y,那么第 15 行不会被执行。
A. 正确 B. 错误
✅ 答案:B(错误)
解析:第 15 行的条件是 a[x] > 0(x 此前已配对),这与「x < y」无关。例如先来 (1,3) 再来 (1,5):x = 1 < 5 且 a[1] = 3 > 0,第 15 行照样执行。
⑤ 若 m 个 x 两两不同,且 m 个 y 两两不同,则输出的值为( )。
A. 2n − 2m B. 2n + 2 C. 2n − 2 D. 2n
✅ 答案:A
解析:每个 x、每个 y 都只出现一次,所以每一对到来时 a[x] = 0、b[y] = 0,全部被接受,匹配数 = m,输出 = 2n − 2m。
⑥ 若 m 个 x 两两不同,且 m 个 y 都相等,则输出的值为( )。
A. 2n − 2 B. 2n C. 2m D. 2n − 2m
✅ 答案:A
解析:所有 y 相同(设为 c)。b[c] 只会保留最小的 x(只有 x 更小时才接受),因此最终匹配数恒为 1,输出 = 2n − 2。

三、完善程序(第 19~20 题,每空 3 分)

完善 1:矩阵变幻(递归分形,第 19 题)难

数字 0 变 00/01 型、1 变 11/10 型(题面图),递归地把矩阵四等分,右下角那块取反。

C++程序代码(带 ①~⑤ 填空标记)
  1. 01#include <cstdio>
  2. 02using namespace std;
  3. 03int n;
  4. 04const int max_size = 1 << 10;
  5. 05
  6. 06int res[max_size][max_size];
  7. 07
  8. 08void recursive(int x, int y, int n, int t) {
  9. 09 if (n == 0) {
  10. 10 res[x][y] = ① ;
  11. 11 return;
  12. 12 }
  13. 13 int step = 1 << (n - 1);
  14. 14 recursive( ② , n - 1, t);
  15. 15 recursive(x, y + step, n - 1, t);
  16. 16 recursive(x + step, y, n - 1, t);
  17. 17 recursive( ③ , n - 1, !t);
  18. 18}
  19. 19
  20. 20int main() {
  21. 21 scanf("%d", &n);
  22. 22 recursive(0, 0, ④ );
  23. 23 int size = ⑤ ;
  24. 24 for (int i = 0; i < size; i++) {
  25. 25 for (int j = 0; j < size; j++)
  26. 26 printf("%d", res[i][j]);
  27. 27 puts("");
  28. 28 }
  29. 29 return 0;
  30. 30}
第①空选项
A. n % 2
B. 0
C. t
D. 1
第②空选项
A. x - step, y - step
B. x, y - step
C. x - step, y
D. x, y
第③空选项
A. x - step, y - step
B. x + step, y + step
C. x - step, y
D. x, y - step
第④空选项
A. n - 1, n % 2
B. n, 0
C. n, n % 2
D. n - 1, 0
第⑤空选项
A. 1 &lt;&lt; (n + 1)
B. 1 &lt;&lt; n
C. n + 1
D. 1 &lt;&lt; (n - 1)
📋 查看各空答案与解析

第①空:C 递归出口要填「该位置写什么数字」。参数 t 表示本次要填的元素,后面几次调用会取反,故选 t。

第②空:D 左上角子矩阵,起点就是 (x, y) 本身,故选 x, y。配合后面两行可知四块依次是 左上、右上(x, y+step)、左下(x+step, y)、右下。

第③空:B 右下角子矩阵,起点 (x + step, y + step),且要填写的元素取反(!t)。

第④空:B 初始调用:从左上角 (0, 0) 开始,变幻 n 次,初始填 0 → recursive(0, 0, n, 0)。

第⑤空:B 矩阵边长:每变幻一次行列都翻倍,初始 1×1,变幻 n 次后边长 2ⁿ = 1 << n。

🪜 以 n = 1 为例(变幻 1 次)
1 主函数调用 recursive(0, 0, 1, 0),step = 1 << 0 = 1
2 左上 recursive(0, 0, 0, 0) → res[0][0] = t = 0
3 右上 recursive(0, 1, 0, 0) → res[0][1] = 0
4 左下 recursive(1, 0, 0, 0) → res[1][0] = 0
5 右下 recursive(1, 1, 0, !0) → res[1][1] = 1
6 矩阵为 00 / 01,size = 1 << 1 = 2,与题面一致 ✓

完善 2:矩形计数(排序 + 去重 + 二分,第 20 题)难

枚举对角线上的两个点作为左下角与右上角,再用二分查找另外两个顶点是否存在。先排序、再去重(完全重合的矩形只算一次)。

C++程序代码(带 ①~⑤ 填空标记)
  1. 01#include <stdio.h>
  2. 02
  3. 03struct point {
  4. 04 int x, y, id;
  5. 05};
  6. 06
  7. 07int equals(struct point a, struct point b){
  8. 08 return a.x == b.x && a.y == b.y;
  9. 09}
  10. 10
  11. 11int cmp(struct point a, struct point b){
  12. 12 return ① ;
  13. 13}
  14. 14
  15. 15void sort(struct point A[], int n){
  16. 16 for (int i = 0; i < n; i++)
  17. 17 for (int j = 1; j < n; j++)
  18. 18 if (cmp(A[j], A[j - 1])){
  19. 19 struct point t = A[j];
  20. 20 A[j] = A[j - 1];
  21. 21 A[j - 1] = t;
  22. 22 }
  23. 23}
  24. 24
  25. 25int unique(struct point A[], int n){
  26. 26 int t = 0;
  27. 27 for (int i = 0; i < n; i++)
  28. 28 if ( ② )
  29. 29 A[t++] = A[i];
  30. 30 return t;
  31. 31}
  32. 32
  33. 33int binary_search(struct point A[], int n, int x, int y){
  34. 34 struct point p;
  35. 35 p.x = x;
  36. 36 p.y = y;
  37. 37 p.id = n;
  38. 38 int a = 0, b = n - 1;
  39. 39 while(a < b){
  40. 40 int mid = ③ ;
  41. 41 if ( ④ )
  42. 42 a = mid + 1;
  43. 43 else
  44. 44 b = mid;
  45. 45 }
  46. 46 return equals(A[a], p);
  47. 47}
  48. 48
  49. 49#define MAXN 1000
  50. 50struct point A[MAXN];
  51. 51
  52. 52int main(){
  53. 53 int n;
  54. 54 scanf("%d", &n);
  55. 55 for (int i = 0; i < n; i++){
  56. 56 scanf("%d %d", &A[i].x, &A[i].y);
  57. 57 A[i].id = i;
  58. 58 }
  59. 59 sort(A, n);
  60. 60 n = unique(A, n);
  61. 61 int ans = 0;
  62. 62 for (int i = 0; i < n; i++)
  63. 63 for (int j = 0; j < n; j++)
  64. 64 if ( ⑤ && binary_search(A, n, A[i].x, A[j].y) && binary_search(A, n, A[j].x, A[i].y)){
  65. 65 ans++;
  66. 66 }
  67. 67 printf("%d\n", ans);
  68. 68 return 0;
  69. 69}
第①空选项
A. a.x != b.x ? a.x &lt; b.x : a.id &lt; b.id
B. a.x != b.x ? a.x &lt; b.x : a.y &lt; b.y
C. equals(a,b) ? a.id &lt; b.id : a.x &lt; b.x
D. equals(a,b) ? a.id &lt; b.id : (a.x != b.x ? a.x &lt; b.x : a.y &lt; b.y)
第②空选项
A. i == 0 || cmp(A[i], A[i - 1])
B. t == 0 || equals(A[i], A[t - 1])
C. i == 0 || !cmp(A[i], A[i - 1])
D. t == 0 || !equals(A[i], A[t - 1])
第③空选项
A. b - (b - a) / 2 + 1
B. (a + b + 1) &gt;&gt; 1
C. (a + b) &gt;&gt; 1
D. a + (b - a + 1) / 2
第④空选项
A. !cmp(A[mid], p)
B. cmp(A[mid], p)
C. cmp(p, A[mid])
D. !cmp(p, A[mid])
第⑤空选项
A. A[i].x == A[j].x
B. A[i].id &lt; A[j].id
C. A[i].x == A[j].x &amp;&amp; A[i].id &lt; A[j].id
D. A[i].x &lt; A[j].x &amp;&amp; A[i].y &lt; A[j].y
📋 查看各空答案与解析

第①空:B 排序规则:按 x 从小到大,x 相同时按 y 从小到大(二维坐标系最常见写法),与 id 无关。

第②空:D 去重:t 记录已保留的不同点数;若 t == 0(第一个点)或当前点与上一个保留的点不重合,就留下它。

第③空:C 二分取下界中点:(a + b) >> 1(右移一位等于整除 2)。这里是「找左边界」的写法,不能 +1,否则与下面的 b = mid 配合会死循环。

第④空:B 右边界左移的条件:A[mid] 排在 p 前面(即 A[mid] < p)时,答案在右半部分 → a = mid + 1。

第⑤空:D 保证枚举的两点分别是左下角与右上角:A[i].x < A[j].x 且 A[i].y < A[j].y(否则退化成线段或点,且会重复计数)。

🪜 整体流程串讲
1 L59 先按 (x, y) 排序,使数组有序,为二分创造条件
2 L60 去重,完全重合的点只留一个(题目规定重合矩形只计一次)
3 L62~L63 双重循环枚举两个点 i、j
4 L64 第 5 空过滤出「i 是左下角、j 是右上角」的组合
5 再用两次二分查找 (A[i].x, A[j].y) 与 (A[j].x, A[i].y) 是否存在 → 即左上、右下两个顶点
6 两点都存在就构成一个轴对齐矩形,ans++