GESP 2026年6月真题编程题详解

> 前言:单看编程题,相较3月份难度要简单很多,像4,5,6级都是很常规的题目,7级暂时缺失题面,8级的编程题也只是模板稍微变形,没有很复杂的思维难度。
1级
T1 税收比例(缺题面)
常规语法题,如果涉及到小数注意保留小数位,目前缺题面不做赘述。
T2 旅行方案
题意从 A 到 B 有三种走法:直达、A 到 C 再飞机到 B、A 到 C 再高铁到 B。给出 4 个价格,求最便宜方案。
思路直接计算三种方案的费用并取最小值即可:
min(直达价, A->C高铁 + C->B飞机, A->C高铁 + C->B高铁)复杂度O(1)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){longlong direct, trainAC, planeCB, trainCB;cin >> direct >> trainAC >> planeCB >> trainCB;cout << min({direct, trainAC + planeCB, trainAC + trainCB}) << '\n';return0;}2级
T1 完全平方数
题意给定整数 l, r,统计区间 [l, r] 内有多少个完全平方数。
思路完全平方数就是 i*i。做法有两种:
直接枚举 i,看i*i是否落在区间内。用公式: floor(sqrt(r)) - ceil(sqrt(l)) + 1,若结果为负则输出0。
题目范围很小,直接枚举就够了。
复杂度O(sqrt(r))。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){longlong l, r;cin >> l >> r;int ans = 0;for (longlong i = 0; i * i <= r; i++) {if (i * i >= l) ans++; }cout << ans << '\n';return0;}T2 打印菱形(缺题面)
常规语法题,注意空格的输出即可。
3级
T1 加密
题意给定数组 S 和长度为 9 的数组 A。对于 S 中每个值 k (0 <= k <= 8),把它替换成 A[k]。
思路这是一个直接映射问题,按位置替换即可。遍历 S,输出 A[S[i]]。
复杂度O(n)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n;cin >> n;vector<int> s(n), a(9);for (int i = 0; i < n; i++) cin >> s[i];for (int i = 0; i < 9; i++) cin >> a[i];for (int i = 0; i < n; i++) {if (i) cout << ' ';cout << a[s[i]]; }cout << '\n';return0;}T2 字符串解密
题意对长度为 n 的字符串逐字符转换:
小写字母变成对应大写字母; 大写字母变成对应小写字母; 数字字符变成 *;其他字符保持不变。
思路逐字符扫描一遍即可。判断字符类型后按规则转换,最后原样拼接输出。
复杂度O(n)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n;string s;cin >> n >> s;for (char &c : s) {if (c >= 'a' && c <= 'z') c = char(c - 'a' + 'A');elseif (c >= 'A' && c <= 'Z') c = char(c - 'A' + 'a');elseif (c >= '0' && c <= '9') c = '*'; }cout << s << '\n';return0;}4级
T1 扫雷
题意给定一个 n x m 的地图和 p 个雷的位置。若当前位置是雷,输出 *;否则输出它 8 邻域内雷的数量。
思路先把雷的位置标记出来,然后对每个非雷格子统计周围 8 个方向的雷数。
可用两个数组表示方向:
dx = [-1,-1,-1,0,0,1,1,1]dy = [-1,0,1,-1,1,-1,0,1]复杂度O(nm + p),或者直接按雷去更新邻格也可以。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n, m, p;cin >> n >> m >> p;vector<vector<char>> grid(n, vector<char>(m, '0'));for (int i = 0; i < p; i++) {int r, c;cin >> r >> c; grid[r - 1][c - 1] = '*'; }int dx[8] = {-1, -1, -1, 0, 0, 1, 1, 1};int dy[8] = {-1, 0, 1, -1, 1, -1, 0, 1};for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) {if (grid[i][j] == '*') continue;int cnt = 0;for (int k = 0; k < 8; k++) {int x = i + dx[k], y = j + dy[k];if (0 <= x && x < n && 0 <= y && y < m && grid[x][y] == '*') { cnt++; } } grid[i][j] = char('0' + cnt); } }for (int i = 0; i < n; i++) {for (int j = 0; j < m; j++) cout << grid[i][j];cout << '\n'; }return0;}T2 身高指数
题意每个朋友有体重和身高,身高指数定义为 体重 / 身高^2。按身高指数从高到低排序并输出。
思路把每个人的 体重、身高 存起来,计算 BMI 后排序。身高是小数,建议用 long double 计算;如果担心精度,可用稳定排序保留原顺序。
复杂度O(n log n)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;structPerson {int weight;string heightText;longdouble height;};intmain(){int n;cin >> n;vector<Person> people(n);for (int i = 0; i < n; i++) {cin >> people[i].weight >> people[i].heightText; people[i].height = stold(people[i].heightText); } stable_sort(people.begin(), people.end(), [](const Person &a, const Person &b) {longdouble ia = a.weight / (a.height * a.height);longdouble ib = b.weight / (b.height * b.height);return ia > ib; });for (auto &p : people) {cout << p.weight << ' ' << p.heightText << '\n'; }return0;}5级
T1 最多糖果
题意有 n 个数,重新排列后,使“每个位置的值被它左边所有数反复累加”后的总和最大。
思路把大数放前面最优。交换论证很直接:如果较小的数在较前面,把它和较大的数交换,总贡献不会变差,通常会更大。所以按降序排序,然后依次累加前缀和,把每次前缀和累加到答案里。
复杂度O(n log n)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n;cin >> n;vector<longlong> a(n);for (int i = 0; i < n; i++) cin >> a[i]; sort(a.begin(), a.end(), greater<longlong>());longlong prefix = 0, ans = 0;for (longlong x : a) { prefix += x; ans += prefix; }cout << ans << '\n';return0;}T2 最大互质和
题意从给定的 n 个正整数中选出两个互质数,使它们的和最大。
思路n <= 1000,直接枚举所有数对,判断 gcd(a[i], a[j]) == 1,维护最大和即可。
复杂度O(n^2 log V)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n;cin >> n;vector<longlong> a(n);for (int i = 0; i < n; i++) cin >> a[i];longlong ans = 0;for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {if (gcd(a[i], a[j]) == 1) { ans = max(ans, a[i] + a[j]); } } }cout << ans << '\n';return0;}6级
T1 蛋糕切割
题意长度为 a 的蛋糕可以切成若干段,长度为 i 的蛋糕价值为 b[i]。求切割后的最大总价值。
思路这是完全背包 / 经典切木棍问题。dp[j] 表示长度为 j 的蛋糕能得到的最大价值。
转移:
dp[j] = max(dp[j], dp[j-i] + b[i])其中 i 可以重复使用,所以枚举长度时,背包容量要正向更新。
复杂度O(a^2)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int a;cin >> a;vector<longlong> value(a + 1), dp(a + 1, 0);for (int i = 1; i <= a; i++) cin >> value[i];for (int piece = 1; piece <= a; piece++) {for (int len = piece; len <= a; len++) { dp[len] = max(dp[len], dp[len - piece] + value[piece]); } }cout << dp[a] << '\n';return0;}T2 满子树计算
题意给定一棵二叉树,每个节点给出左右孩子编号(不存在则为 0)。统计其中有多少个节点为根的子树是满二叉树。
思路先找到整棵树的根节点,再自底向上判断每个子树:
叶子节点:是满二叉树,高度为 1; 若左右子树都存在,且左右子树都满二叉树,并且高度相同,则当前子树也是满二叉树; 其他情况都不是。
遍历时顺便计数即可。
复杂度O(n)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;intmain(){int n;cin >> n;vector<int> leftChild(n + 1), rightChild(n + 1), isChild(n + 1, 0);for (int i = 1; i <= n; i++) {cin >> leftChild[i] >> rightChild[i];if (leftChild[i]) isChild[leftChild[i]] = 1;if (rightChild[i]) isChild[rightChild[i]] = 1; }int root = 1;for (int i = 1; i <= n; i++) {if (!isChild[i]) { root = i;break; } }vector<int> order; order.reserve(n);stack<int> st; st.push(root);while (!st.empty()) {int u = st.top(); st.pop(); order.push_back(u);if (leftChild[u]) st.push(leftChild[u]);if (rightChild[u]) st.push(rightChild[u]); }vector<int> height(n + 1, 0);vector<bool> full(n + 1, false);int ans = 0; reverse(order.begin(), order.end());for (int u : order) {int l = leftChild[u], r = rightChild[u];if (l == 0 && r == 0) { full[u] = true; height[u] = 1; } elseif (l != 0 && r != 0 && full[l] && full[r] && height[l] == height[r]) { full[u] = true; height[u] = height[l] + 1; } else { height[u] = max(height[l], height[r]) + 1; }if (full[u]) ans++; }cout << ans << '\n';return0;}7级
暂时缺失
8级
T1 组合数计算
题意计算 C(n-1, m-1) mod (1e9+7)。约束保证 min(m-1, n-m) <= 2e6。
思路利用组合数对称性:
C(n-1, m-1) = C(n-1, k), k = min(m-1, n-m)然后计算:
num = (n-1) * (n-2) * ... * (n-k)den = k!ans = num * den^(mod-2) mod mod其中 den^(mod-2) 用费马小定理求逆元。
复杂度O(k + log mod),k <= 2e6。
参考代码
#include<bits/stdc++.h>usingnamespacestd;constlonglong MOD = 1000000007LL;longlongmodPow(longlong a, longlong e){longlong ans = 1; a %= MOD;while (e > 0) {if (e & 1) ans = ans * a % MOD; a = a * a % MOD; e >>= 1; }return ans;}intmain(){longlong n, m;cin >> n >> m;longlong k = min(m - 1, n - m);longlong numerator = 1, denominator = 1;for (longlong i = 0; i < k; i++) { numerator = numerator * ((n - 1 - i) % MOD + MOD) % MOD; denominator = denominator * (i + 1) % MOD; }longlong ans = numerator * modPow(denominator, MOD - 2) % MOD;cout << ans << '\n';return0;}T2 网格上的有限距离最小生成树
题意平面上有 N 个点,边权是曼哈顿距离。只允许使用长度不超过 L 的边,求把所有点连通的最小总长度;若无法连通,输出 -1。
思路N <= 1000,可以直接建完全图:
枚举所有点对,计算曼哈顿距离; 若距离 <= L,就加入边集;对边集按权值排序,跑 Kruskal。
如果最后没选满 N-1 条边,说明无法连通,输出 -1。
复杂度O(N^2 log N)。
参考代码
#include<bits/stdc++.h>usingnamespacestd;structDSU {vector<int> parent, size; DSU(int n) : parent(n), size(n, 1) { iota(parent.begin(), parent.end(), 0); }intfind(int x){while (x != parent[x]) { parent[x] = parent[parent[x]]; x = parent[x]; }return x; }boolunite(int a, int b){ a = find(a); b = find(b);if (a == b) returnfalse;if (size[a] < size[b]) swap(a, b); parent[b] = a; size[a] += size[b];returntrue; }};structEdge {int u, v;longlong w;};intmain(){int n;longlong limit;cin >> n >> limit;vector<pair<longlong, longlong>> point(n);for (int i = 0; i < n; i++) {cin >> point[i].first >> point[i].second; }vector<Edge> edges;for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {longlong dist = llabs(point[i].first - point[j].first) + llabs(point[i].second - point[j].second);if (dist <= limit) edges.push_back({i, j, dist}); } } sort(edges.begin(), edges.end(), [](const Edge &a, const Edge &b) {return a.w < b.w; });DSU dsu(n);longlong ans = 0;int used = 0;for (const Edge &e : edges) {if (dsu.unite(e.u, e.v)) { ans += e.w; used++; } }cout << (used == n - 1 ? ans : -1) << '\n';return0;}