
记录一道 GESP 2025年3月 的模拟真题。这类题在考试里属于必得分项核心就那几行代码关键是别在小细节上丢分。题目来源ACGO A46120 2025年3月 四级赛事场次2025年3月 四级一、题目信息题目名称荒地开垦赛事场次2025年3月 四级难度定位四级涉及知识点模拟 枚举题目链接https://www.acgo.cn/problemset/info/46120先说坑点不提前知道必错枚举范围的确定如何用循环穷举全部可能。二维题目注意下标从 0 还是 1 开始边界要留够。题意简述小杨有一大片荒地,可以表示为一个 n 行 m 列的网格图小杨想要开垦这块荒地,但荒地中一些位置存在杂物,对于一块不存在杂物的荒地,该荒地可以开垦当且仅当其上 下左右四个方向相邻的格子均不存在杂物小杨可以选择至多一个位置,清除该位置的杂物,移除杂物后该位置变为荒地小杨想知道在清除至多一个位置的 杂物的情况下,最多能够开垦多少块荒地前置知识做题之前我们先把几个关键概念说清楚这样后面的代码才好理解。模拟题的解法把题目描述的操作流程一步一步翻译成代码。关键是不要漏掉题目里的任何条件建议先把流程在纸上走一遍再写码。二、思路分析先看清楚题目要我们做什么把题目读两遍我们提取出关键信息输入是什么、要输出什么、有哪些约束条件。这道题考查的是模拟属于这类题里比较基础的一道把题目要求一步步翻译成代码逻辑就能解决。我的思考过程读完题之后我的第一反应是这样的给定一个 n× m 网格.表示荒地#表示杂物。一块荒地可以开垦当且仅当它上下左右相邻的格子都不是#。你最多可以清除一个位置的杂物把一个#变成.。求清除至多一个杂物后最多能开垦多少块荒地。官方std的核心做法是把“最多清除一个#”转化为“统计每个#被清除后能额外解锁多少块可开垦荒地”。顺着这个方向往下想就得到完整做法对每个格子 (i,j)统计它四邻域中#的个数num若mat[i][j].且num0说明它本来就可开垦直接计入ans。若mat[i][j].且num1说明它只被唯一的一个相邻#阻挡如果清除这个相邻#该格就会变成可开垦。因此把贡献 1 记到“那个相邻#”上a[block]。若mat[i][j]#且num0说明它周围没有#如果把它清除为.它自己也会满足四邻域无#因此它本身会成为可开垦格记a[i][j]。这样ans表示“不清除时已可开垦的数量”而a[x][y]表示“清除 (x,y) 这个#后能新增的可开垦数量”。最终答案为ansmax a[x][y]整体只需遍历网格常数次时间复杂度 O(nm)。###需要说明的是上面这个思路是把题目要求直译成代码得到的没有用到什么高级技巧。对于这类基础题读准题意加写对边界比追求巧妙解法更重要因为考试里这种题是必须拿满分的。三、完整代码 逐行注释#includebits/stdc.h using namespace std; const int N 1005; char mat[N][N]; int a[N][N]; const int d[4][2] {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; int main() { int n, m, ans 0; scanf(%d%d, n, m); assert(1 n n 1000); assert(1 m m 1000); for (int i 1; i n; i ) // 遍历 scanf(%s, mat[i] 1); for (int i 1; i n; i ) // 遍历 for (int j 1; j m; j ) { // 遍历 int num 0, p -1; for (int k 0; k 4; k ) // 遍历 if (mat[i d[k][0]][j d[k][1]] #) // 判断 num , p k; if (mat[i][j] . num 1) // 判断 a[i d[p][0]][j d[p][1]] ; else if (mat[i][j] . num 0) // 判断 ans ; else if (mat[i][j] # num 0) // 判断 a[i][j] ; } int mx 0; // 初始化 for (int i 1; i n; i ) // 遍历 for (int j 0; j m; j ) // 遍历 mx max(mx, a[i][j]); cout ans mx endl; // 输出 return 0; }四、代码分段拆解完整代码在上面下面把它拆成几块逐块说明。第一步引入头文件#includebits/stdc.h using namespace std;#include iostream提供输入输出功能using namespace std;让我们能直接写cin、cout而不用加前缀。这两行是几乎所有 C 程序的开头照写即可。第二步读入数据scanf(%d%d, n, m); scanf(%s, mat[i] 1);注意变量的类型要能装下题目的数据。数据可能超过 21 亿时要改用long long。第三步核心处理逻辑for (int i 1; i n; i ) for (int i 1; i n; i ) for (int j 1; j m; j ) { for (int k 0; k 4; k )这一段是整道题的关键也是模拟的体现。看循环的三个要素从哪里开始、什么时候结束、每次怎么变化。这三个要素任何一个写错结果都会不对。第四步按要求输出cout ans mx endl;输出格式必须和题目要求的完全一致。很多同学算法完全正确却因为少了一个换行或者空格多寡不对而 WA这种分丢得最可惜。五、实例模拟下面用样例数据走一遍流程你能看到每一步变量是怎么变化的。以题目的第一组样例为例样例输入3 5 ..... .#..# .....样例输出11把这份输入代进代码程序会先把数据依次读入然后进入循环逐个判断把满足条件的值累积起来最后按格式输出。建议你对照着代码在纸上走一遍前两次循环确认自己对每一步的理解都和程序一致。六、踩坑总结下面是做这道题时最容易出错的地方对照自己的代码检查一下变量类型选错虽然本题范围不大但养成习惯——凡是不确定范围时累加变量一律用long long成本为零但能保命。输出格式不符题目要求输出几行就输出几行行末换行、数字之间的空格都要严格对齐算法对了但格式错了同样判 WA这种分丢得最冤。特殊情况没特判把最小数据、最大数据、答案恰好等于 0 的情况各测一遍。特别是边界输入出题人最喜欢在这里设陷阱。七、知识点拓展把这题的经验提炼一下以后遇到同类题可以直接套用本题考查模拟的基本写法这类题在考试中属于必得分项要练到能默写。写完代码后建议自己造几组边界数据测试特别是最小值和最大值。同一知识点在不同场次反复出现把这道题的写法吃透后面遇到同类题可以直接套用。八、适用人群适合正在备考 四级、想确认自己模拟基础是否扎实的同学。以上就是这道题的全部内容。这个系列会按考试场次逐题更新觉得有帮助的话可以关注一下也欢迎在评论区留下你的解法。