2980 字
15 分钟
GESP 2025年C++四级编程题解析
2025/03/22
2025/09/29

202509-1 排兵布阵#

题目描述

作为将军,你自然需要合理地排兵布阵。地图可以视为 nnmm 列的网格,适合排兵的网格以 1 标注,不适合排兵的网格以 0 标注。现在你需要在地图上选择一个矩形区域排兵,这个矩形区域内不能包含不适合排兵的网格。请问可选择的矩形区域最多能包含多少网格?

输入格式

第一行,两个正整数 n,mn, m,分别表示地图网格的行数与列数。

接下来 nn 行,每行 mm 个整数 ai,1,ai,2,,ai,ma_{i,1}, a_{i,2}, \ldots, a_{i,m},表示各行中的网格是否适合排兵。

输出格式

一行,一个整数,表示适合排兵的矩形区域包含的最大网格数。

样例输入 1

4 3
0 1 1
1 0 1
0 1 1
1 1 1

样例输出 1

4

样例输入 2

3 5
1 0 1 0 1
0 1 0 1 0
0 1 1 1 0

样例输出 2

3

提示

对于所有测试点,保证 1n,m121 \leq n, m \leq 120ai,j10 \leq a_{i,j} \leq 1

代码解析

没有技巧,根据题意使用模拟法解题即可,简而言之,可选择的矩形区域必须全都是 1,只需要以每个点 arr[i][j] 作为起点,再以这个点为矩形左上角,依次枚举右下角的点 arr[x][y],遍历这个矩形区域,看这个区域内是否全部都是 1,如果全部都是 1 则统计这个矩形区域内点的数量 (x-i+1)*(y-j+1),求最大值。

#include<bits/stdc++.h>
using namespace std;
bool arr[15][15] = {0};
int n, m;
// 封装 sum 函数统计以 arr[i][j] 作为左上角的矩形中全是 1 的最大矩形
int sum(int i, int j) {
int cnt = 0;
for(int x = i; x <= n; x++)
for(int y = j; y <= m; y++) {
bool flag = true;
for(int a = i; a <= x; a++)
for(int b = j; b <= y; b++)
if (arr[a][b] == 0)
flag = false;
if (flag)
cnt = max(cnt, (x-i+1)*(y-j+1));
}
return cnt;
}
int main() {
cin >> n >> m;
int ans = 0;
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++)
cin >> arr[i][j];
for(int i = 1; i <= n; i++)
for(int j = 1; j <= m; j++) {
ans = max(ans, sum(i, j));
}
cout << ans;
return 0;
}

202509-2 最长连续段#

题目描述

对于 kk 个整数构成的数组 [b1,b2,,bk][b_1, b_2, \ldots, b_k],如果对 1i<k1 \leq i < k 都有 bi+1=bi+1b_{i+1} = b_i + 1,那么称数组 bb 是一个连续段。

给定由 nn 个整数构成的数组 [a1,a2,,an][a_1, a_2, \ldots, a_n],你可以任意重排数组 aa 中元素顺序。请问在重排顺序之后,aa 所有是连续段的子数组中,最长的子数组长度是多少?

例如,对于数组 [1,0,2,4][1, 0, 2, 4],可以将其重排为 [4,0,1,2][4, 0, 1, 2],有以下 1010 个子数组:

[4],[0],[1],[2],[4,0],[0,1],[1,2],[4,0,1],[0,1,2],[4,0,1,2][4], [0], [1], [2], [4, 0], [0, 1], [1, 2], [4, 0, 1], [0, 1, 2], [4, 0, 1, 2]

其中除 [4,0],[4,0,1],[4,0,1,2][4, 0], [4, 0, 1], [4, 0, 1, 2] 以外的子数组均是连续段,因此是连续段的子数组中,最长子数组长度为 3。

输入格式

第一行,一个正整数 nn,表示数组长度。

第二行,nn 个整数 a1,a2,,ana_1, a_2, \ldots, a_n,表示数组中的整数。

输出格式

一行,一个整数,表示数组 aa 重排顺序后,所有是连续段的子数组的最长长度。

样例输入 1

4
1 0 2 4

样例输出 1

3

样例输入 2

9
9 9 8 2 4 4 3 5 3

样例输出 2

4

提示

对于 40%40\% 的测试点,保证 1n81 \leq n \leq 8

对于所有测试点,保证 1n1051 \leq n \leq 10^5109ai109-10^9 \leq a_i \leq 10^9

代码解析

连续段的意思是 1,2,3,4 …

解题思路就是先对原数组进行排序,然后确定一个变量 last 来记录上一个数字,如果数 a[i] == last ,就跳过继续找,如果 a[i] == last + 1 则连续段长度加 1,如果 a[i] 小于 last 或大于 last + 1 说明当前连续段已经最长,记录最大值,重新开始统计下一个连续段

#include<bits/stdc++.h>
using namespace std;
int main() {
int a[100005];
int n;
cin >> n;
for(int i = 0; i < n; i++)
cin >> a[i];
sort(a, a+n);
int last = a[0], m = 1, cnt = 1;
for(int i = 1; i < n; i++) {
if (a[i] == last) {
continue;
} else if (a[i] == last + 1) {
m++;
last = a[i];
} else {
cnt = max(cnt, m);
m = 1;
last = a[i];
}
}
cnt = max(cnt, m);
cout << cnt;
return 0;
}

202506-1 画布裁剪#

题目描述

小 A 在高为 hh 宽为 ww 的矩形画布上绘制了一幅画。由于画布边缘留白太多,小 A 想适当地裁剪画布,只保留画的主体。具体来说,画布可以视为 hhww 列的字符矩阵,其中的字符均为 ASCII 码位于 3312633 \sim 126 之间的可见字符,小 A 只保留画布中由第 x1x_1 行到第 x2x_2 行、第 y1y_1 列到第 y2y_2 列构成的子矩阵。

小 A 将画布交给了你,你能帮他完成画布的裁剪吗?

输入格式

第一行,两个正整数 h,wh, w,分别表示画布的行数与列数。

第二行,四个正整数 x1,x2,y1,y2x_1, x_2, y_1, y_2,表示保留的行列边界。

接下来 hh 行,每行一个长度为 ww 的字符串,表示画布内容。

输出格式

输出共 x2x1+1x_2 - x_1 + 1 行,每行一个长度为 y2y1+1y_2 - y_1 + 1 的字符串,表示裁剪后的画布。

样例输入 1

3 5
2 2 2 4
.....
.>_<.
.....

样例输出 1

>_<

样例输入 2

5 5
1 2 3 4
AbCdE
fGhIk
LmNoP
qRsTu
VwXyZ

样例输出 2

Cd
hI

提示

对于所有测试点,保证 1h,w1001 \leq h, w \leq 1001x1x2h1 \leq x_1 \leq x_2 \leq h1y1y2w1 \leq y_1 \leq y_2 \leq w

代码解析

这道题就是送分题,注意我们只需要输出题目要求输出的部分即可,不是真的需要将原数组裁剪。。。

#include<bits/stdc++.h>
using namespace std;
int main() {
char a[101][101];
int h, w, x1, x2, y1, y2;
cin >> h >> w;
cin >> x1 >> x2 >> y1 >> y2;
for (int i = 1; i <= h; i++)
for (int j = 1; j <= w; j++)
cin >> a[i][j];
for (int i = x1; i <= x2; i++) {
for (int j = y1; j <= y2; j++)
cout << a[i][j];
cout << endl;
}
return 0;
}

202506-2 排序#

题目描述

体育课上有 nn 名同学排成一队,从前往后数第 ii 位同学的身高为 hih_i,体重为 wiw_i。目前排成的队伍看起来参差不齐,老师希望同学们能按照身高从高到低的顺序排队,如果身高相同则按照体重从重到轻排序。在调整队伍时,每次只能交换相邻两位同学的位置。老师想知道,最少需要多少次交换操作,才能将队伍调整成目标顺序。

输入格式

第一行,一个正整数 nn,表示队伍人数。

接下来 nn 行,每行两个正整数 hih_iwiw_i,分别表示第 ii 位同学的身高和体重。

输出格式

输出一行,一个整数,表示最少需要的交换次数。

样例输入 1

5
1 60
3 70
2 80
4 55
4 50

样例输出 1

8

样例输入 2

5
4 0
4 0
2 0
3 0
1 0

样例输出 2

1

提示

对于所有测试点,保证 1n30001 \leq n \leq 30000hi,wi1090 \leq h_i, w_i \leq 10^9

代码解析

这道题考察的是结构体数组的冒泡排序,注意排序中交换的条件有两条,一个是只看身高,另一个是身高相同的时候看体重,这是为数不多的考集中直接考察排序的题目,说明排序在编程题中考察的概率还是有的。

#include<bits/stdc++.h>
using namespace std;
struct student {
int h, w;
}a[3005];
int main() {
int n, cnt = 0;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> a[i].h >> a[i].w;
// 冒泡排序
for (int i = 1; i <= n-1; i++)
for (int j = 1; j <= n-i; j++)
if (a[j].h < a[j+1].h || a[j].h == a[j+1].h && a[j].w < a[j+1].w) {
swap(a[j], a[j+1]);
cnt++;
}
cout << cnt;
return 0;
}

202503-1 荒地开垦#

题目描述

小杨有一大片荒地,可以表示为一个 nnmm 列的网格图。

小杨想要开垦这块荒地,但荒地中一些位置存在杂物,对于一块不存在杂物的荒地,该荒地可以开垦当且仅当其上下左右四个方向相邻的格子均不存在杂物。

小杨可以选择至多一个位置,清除该位置的杂物,移除杂物后该位置变为荒地。小杨想知道在清除至多一个位置的杂物的情况下,最多能够开垦多少块荒地。

输入格式

第一行包含两个正整数 n,mn, m,含义如题面所示。

之后 nn 行,每行包含一个长度为 mm 且仅包含字符 .# 的字符串。如果为 .,代表该位置为荒地;如果为 #,代表该位置为杂物。

输出格式

输出一个整数,代表在清除至多一个位置的杂物的情况下,最多能够开垦的荒地块数。

样例输入 1

3 5
.....
.#..#
.....

样例输出 1

11

提示

【样例解释】

移除第二行从左数第二块空地的杂物后:

.....
....#
.....

第一行从左数前 44 块荒地,第二行从左数前 33 块荒地,第三行从左数前 44 块荒地,均可开垦,4+3+4=114+3+4=11

【数据范围】

对于全部数据,有 1n,m10001\leq n,m\leq 1000

代码解析

今年第一次四级考题就使用了模拟法,没有什么技巧,认真读题暴力枚举即可,这里的偏移数组 dx[]dy[] 不是必要的,如果觉得思路受阻可以直接简单粗暴进行四个方向,对于代码的运行效率没有什么影响。

#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m, max = 0;
char a[1005][1005];
int dx[] = {0, 0, 1, -1};
int dy[] = {1, -1, 0, 0};
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++) {
cin >> a[i][j];
a[i][0] = a[i][m+1] = '.';
a[0][j] = a[n+1][j] = '.';
}
int count = 0;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++){
if (a[i][j] == '#') continue;
bool flag = true;
for (int k = 0; k < 4; k++)
if (a[i+dx[k]][j+dy[k]] == '#')
flag = false;
if (flag) count++;
}
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++){
int max_count = count;
if (a[i][j] == '#') {
bool flag = true;
for (int k = 0; k < 4; k++) {
int x = i+dx[k], y = j+dy[k];
if (a[x][y] == '#') {flag = false; break;}
if (x >= 1 && x <= n && y >= 1 && y <= m) {
int cnt = 0;
for (int d = 0; d < 4; d++)
if (a[x+dx[d]][y+dy[d]] == '#')
cnt++;
if (cnt == 1) max_count++;
}
}
if (flag) max_count++;
}
max = (max_count > max ? max_count : max);
}
cout << max;
return 0;
}

202503-2 二阶矩阵#

题目描述

小 A 有一个 nnmm 列的矩阵 AA

小 A 认为一个 2×22 \times 2 的矩阵 DD 是好的,当且仅当 D1,1×D2,2=D1,2×D2,1D_{1,1} \times D_{2,2} = D_{1,2} \times D_{2,1}。其中 Di,jD_{i,j} 表示矩阵 DD 的第 ii 行第 jj 列的元素。

小 A 想知道 AA 中有多少个好的子矩阵。

输入格式

第一行,两个正整数 n,mn, m

接下来 nn 行,每行 mm 个整数 Ai,1,Ai,2,,Ai,mA_{i,1}, A_{i,2}, \ldots, A_{i,m}

输出格式

一行,一个整数,表示 AA 中好的子矩阵的数量。

样例输入 1

3 4
1 2 1 0
2 4 2 1
0 3 3 0

样例输出 1

2

提示

【样例解释】

样例中好的子矩阵如下:

【数据范围】

对于所有测试点,保证 1n5001\leq n\leq 5001m5001\leq m\leq 500100Ai,j100-100\leq A_{i,j}\leq 100

代码解析

枚举法啦,枚举就可以啦,没有啥难度嗷~ 注意细心一点,坐标之间的关系别搞混了。

#include<bits/stdc++.h>
using namespace std;
int main() {
int n, m, a[505][505], cnt = 0;
cin >> n >> m;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
cin >> a[i][j];
for (int i = 1; i <= n-1; i++)
for (int j = 1; j <= m-1; j++)
if (a[i][j] * a[i+1][j+1] == a[i][j+1] * a[i+1][j])
cnt++;
cout << cnt;
return 0;
}
GESP 2025年C++四级编程题解析
https://yezi.press/posts/gesp/gesp-cpp4-2025/
作者
Yezi 叶子
发布于
2025/03/22
许可协议
CC BY-NC-SA 4.0