2021年CSP-J初赛真题及答案解析(完善程序2)
第 2 题
矩形计数:平面上有 (n) 个关键点,求有多少个四条边都和 (x) 轴或者 (y) 轴平行的矩形,满足四个顶点都是关键点。给出的关键点可能有重复,但完全重合的矩形只计一次。
试补全枚举算法。
cpp
#include <iostream>
using namespace std;
struct point {
int x, y, id;
};
bool equals(point a, point b) {
return a.x == b.x && a.y == b.y;
}
bool cmp(point a, point b) {
return ①;
}
void sort(point A[], int n) {
for (int i = 0; i < n; i++) {
for (int j = 1; j < n; j++) {
if (cmp(A[j], A[j - 1])) {
point t = A[j];
A[j] = A[j - 1];
A[j - 1] = t;
}
}
}
}
int unique(point A[], int n) {
int t = 0;
for (int i = 0; i < n; i++) {
if (②)
A[t++] = A[i];
}
return t;
}
bool binary_search(point A[], int n, int x, int y) {
point p;
p.x = x;
p.y = y;
p.id = n;
int a = 0, b = n - 1;
while (a < b) {
int mid = ③;
if (④)
a = mid + 1;
else
b = mid;
}
return equals(A[a], p);
}
const int MAXN = 1000;
point A[MAXN];
int main() {
int n;
cin >> n;
for (int i = 0; i < n; i++) {
cin >> A[i].x >> A[i].y;
A[i].id = i;
}
sort(A, n);
n = unique(A, n);
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < n; j++) {
if (⑤ && binary_search(A, n, A[i].x, A[j].y) && binary_search(A, n, A[j].x, A[i].y)) {
ans++;
}
}
}
cout << ans << endl;
return 0;
}
① 处应填( )
A. a.x != b.x ? a.x < b.x : a.id < b.id
B. a.x != b.x ? a.x < b.x : a.y < b.y
C. equals(a, b) ? a.id < b.id : a.x < b.x
D. equals(a, b) ? a.id < b.id : (a.x != b.x ? a.x < b.x : a.y < 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) >> 1
C. (a + b) >> 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 < A[j].id
C. A[i].x == A[j].x && A[i].id < A[j].id
D. A[i].x < A[j].x && A[i].y < A[j].y
答案
- ① B
- ② D
- ③ C
- ④ B
- ⑤ D
解析
变量与函数作用
cmp(a, b):定义点的严格弱序,用于排序和二分查找。sort(A, n):冒泡排序,按cmp确定的顺序将点排好。unique(A, n):对已排序的数组去重,返回去重后元素个数。binary_search(A, n, x, y):在有序数组A中二分查找坐标为(x, y)的点,存在返回true。- 主函数:排序、去重,然后枚举所有可能构成矩形左下角与右上角的点对,检查另外两个顶点是否存在,计数。
① 排序比较规则
排序时必须按点坐标大小排序,通常按 x 升序,x 相同则按 y 升序。
- 若
a.x != b.x,按a.x < b.x决定。 - 若
a.x == b.x,按a.y < b.y决定。
选项 B 完全符合,且当两点完全相同时,a.y < b.y为false,满足严格弱序要求。
其他选项引入了id或equals,会打乱坐标顺序,导致二分查找错误。
答案:B
② 去重条件
去重时,当前元素 A[i] 应该被保留,当且仅当它是第一个元素(t == 0)或者它不等于 已保留的最后一个元素 A[t - 1]。
因此条件应为:t == 0 || !equals(A[i], A[t - 1])。
选项 D 正确。选项 B 是相等时保留,错误;A、C 使用 cmp 无法正确判断相等。
答案:D
③ 二分查找中间位置
标准二分查找中,mid = (a + b) / 2,在 C++ 中可写作 (a + b) >> 1。
选项 C 正确。选项 B 是上取整,会破坏二分查找的稳定性;选项 A、D 写法错误。
答案:C
④ 二分查找移动方向
标准二分查找中,若 A[mid] < p,说明目标在右半部分,令 a = mid + 1;否则令 b = mid。
这里的"小于"关系由 cmp(A[mid], p) 表示(若返回 true,则 A[mid] 排在 p 前面,即小于)。
因此 if (cmp(A[mid], p)) a = mid + 1;。
选项 B 正确。选项 A 是 !cmp(A[mid], p),表示不小于,会令方向相反;C、D 比较方向颠倒。
答案:B
⑤ 避免矩形重复计数
一个矩形的四个顶点中,有且仅有一对点可作为左下角 和右上角 (x 和 y 都较小/较大)。
枚举时只统计 A[i].x < A[j].x 且 A[i].y < A[j].y 的情况,这样每个矩形只会被计数一次。
同时,检查另外两个点 (A[i].x, A[j].y) 和 (A[j].x, A[i].y) 是否存在。
选项 D 正确。其他选项如 A、B、C 无法保证唯一且正确的配对。
答案:D
更多内容请关注专栏:信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
【秘籍汇总】(完整csp信奥赛C++学习资料):
1、csp/信奥赛C++,完整信奥赛系列课程(永久学习):
https://edu.csdn.net/lecturer/7901 点击跳转

2、CSP信奥赛C++竞赛拿奖视频课:
https://edu.csdn.net/course/detail/40437 点击跳转

https://edu.csdn.net/course/detail/41081 点击跳转

3、csp信奥赛高频考点知识详解及案例实践:
CSP信奥赛C++动态规划:
https://blog.csdn.net/weixin_66461496/category_13096895.html点击跳转
CSP信奥赛C++标准模板库STL:
https://blog.csdn.net/weixin_66461496/category_13108077.html 点击跳转
信奥赛C++提高组csp-s知识详解及案例实践:
https://blog.csdn.net/weixin_66461496/category_13113932.html 点击跳转
4、csp信奥赛冲刺一等奖有效刷题题解:
信奥赛C++普及组CSP-J一等奖通关刷题题单及题解:
https://blog.csdn.net/weixin_66461496/category_12673810.html 点击跳转
信奥赛C++普及组csp-j初赛&复赛真题题解(持续更新): https://blog.csdn.net/weixin_66461496/category_12808781.html 点击跳转
信奥赛C++提高组csp-s初赛&复赛真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13125089.html 点击跳转
5、GESP C++考级真题题解:

GESP(C++ 一级+二级+三级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12858102.html 点击跳转

GESP(C++ 四级+五级+六级)真题题解(持续更新):https://blog.csdn.net/weixin_66461496/category_12869848.html 点击跳转

GESP(C++ 七级+八级)真题题解(持续更新):
https://blog.csdn.net/weixin_66461496/category_13117178.html 点击跳转
· 文末祝福 ·
cpp
#include<bits/stdc++.h>
using namespace std;
int main(){
cout<<"跟着王老师一起学习信奥赛C++";
cout<<" 成就更好的自己! ";
cout<<" csp信奥赛一等奖属于你! ";
return 0;
}
