题解|GESP2026年9月C++八级真题解析

四季读书网 8 0
题解|GESP2026年9月C++八级真题解析

点击 GESP 真题解析合集 可以查看历届 GESP 真题解析。

1. 单选题(每题 2 分,共 30 分)

题解|GESP2026年9月C++八级真题解析-第1张图片-四季读书网

【答案】: B。

【解析】: 数字模  可以分为三组 。三位数能被  整除,需要三位数字之和能被  整除。由于每组只有两个数字,只能从上述三组中各选一个数字。

  • 选到数字 :共有  组,每组有  种合法排列,共  个。
  • 选到数字 :共有  组,每组有  种合法排列,共  个。

因此共有  个。

题解|GESP2026年9月C++八级真题解析-第2张图片-四季读书网

【答案】: C。

【解析】: 把甲乙看成一个整体,共  个人围成一个圈的圆排列为 ,甲乙内部有  种方案,共有  种方案。

题解|GESP2026年9月C++八级真题解析-第3张图片-四季读书网

【答案】: B。

【解析】: 典型的区间 DP 问题,何必顺序为  合并, 合并, 合并。

题解|GESP2026年9月C++八级真题解析-第4张图片-四季读书网

【答案】: A。

【解析】: 先序序列的第一个元素就是根,然后中序中找到根,根的左边是左子树,右边是右子树,递归操作。

题解|GESP2026年9月C++八级真题解析-第5张图片-四季读书网

【答案】: B。

【解析】:

  • A 选项错误,普通快速幂无法处理任意负指数。
  • B 选项正确。
  • C 选项错误,模数可以是合数。
  • D 选项错误,迭代实现通常需要  的空间。
题解|GESP2026年9月C++八级真题解析-第6张图片-四季读书网

【答案】: B。

【解析】: 杨辉三角数就是组合数,答案为 

题解|GESP2026年9月C++八级真题解析-第7张图片-四季读书网

【答案】: C。

【解析】: 简单数学题。容易得到长和宽分别为  和 ,面积为 

题解|GESP2026年9月C++八级真题解析-第8张图片-四季读书网

【答案】: D。

【解析】: 简单数学题。容易得到 ,答案为 

题解|GESP2026年9月C++八级真题解析-第9张图片-四季读书网

【答案】: A。

【解析】:

  • A 选项正确,Prim 算法时间复杂度与顶点相关,Kruskal 需要对边排序。
  • B 选项错误,最小生成树不一定相同。
  • C 选项错误,Kruskal 可以用邻接表存图。
  • D 选项错误,Prim 也可以处理无向图。
题解|GESP2026年9月C++八级真题解析-第10张图片-四季读书网

【答案】: B。

【解析】: 按照边权从小到大加入不成环的边。

题解|GESP2026年9月C++八级真题解析-第11张图片-四季读书网

【答案】: A。

【解析】: 距离小的需要先出队,堆中保存顶点编号与距离。

题解|GESP2026年9月C++八级真题解析-第12张图片-四季读书网

【答案】: A。

【解析】: 关于 Floyd 算法的理解。

题解|GESP2026年9月C++八级真题解析-第13张图片-四季读书网

【答案】: C。

【解析】: 简单比大小。

题解|GESP2026年9月C++八级真题解析-第14张图片-四季读书网

【答案】: D。

【解析】: 次差分,每次操作 ,求前缀和是 ,总时间复杂度为 

题解|GESP2026年9月C++八级真题解析-第15张图片-四季读书网

【答案】: D。

【解析】: 关于C++继承中构造函数和析构函数的理解。子类实体化会先调用父类的构造函数再调用子类的构造函数,释放内存时会先调用子类的析构函数再调用父类的析构函数。

2. 判断题(每题 2 分,共 20 分)

2.1 判断题题面

题解|GESP2026年9月C++八级真题解析-第16张图片-四季读书网

2.2 判断题解析

第 1 题。排列问题。

第 2 题。根据二项式定理,取  和  容易证明。

第 3 题。最小生成树可能唯一,例如本来就是一棵树,边权都相同。

第 4 题。朴素的 Dijkstra 是  的。

第 5 题。排堆其实就是一种选择排序,不稳定。

第 6 题。唯一分解定理。

第 7 题。循环队列的基础知识。

第 8 题。私有继承,基类的 public 成员在派生类变为 private 的。

第 9 题。滚动数组的特点。

第 10 题。可以用海伦公式计算。

3. 编程题(每题 25 分,共 50 分)

3.1 编程题 1(生成树计数)

题解|GESP2026年9月C++八级真题解析-第17张图片-四季读书网

分析

这类图通常称为仙人掌图:每条边至多属于一个简单环。

答案为 ,其中 (|C|) 表示环的边数。

对于不属于任何环的边,它是桥。删除桥会使图不连通,所以所有生成树都必须选择这些边。

对于一个长度为  的简单环,如果保留全部  条边,生成树中会出现环;必须从中删除一条边;删除任意一条边后,环变成一条链,仍然连通;因此这个环有  种选择。

由于每条边至多属于一个简单环,不同环之间的选择相互独立,所以把所有环长相乘即可。

可以用 DFS 找环,时间复杂度为 

代码

#include<bits/stdc++.h>
usingnamespacestd;

using ll = longlong;
constint maxn = 1e5 + 5, mod = 998244353;
int dep[maxn], n, m;
ll ans = 1;
bool vis[maxn];

structnode {
int v, id;
};
vector<node> g[maxn];

voiddfs(int u, int par){
    vis[u] = true;
for(auto [v, id]: g[u]) {
if(id == par) continue;
if(!vis[v]) {
            dep[v] = dep[u] + 1;
            dfs(v, id);
        } elseif(dep[v] < dep[u]) { // 反祖边
int len = dep[u] - dep[v] + 1;
            ans = ans * len % mod;
        }
    }
}

intmain(){
cin>>n>>m;
for(int i = 1; i <= m; ++i) {
int u, v;
cin>>u>>v;
        g[u].push_back({v, i}), g[v].push_back({u, i});
    }
    dfs(10);
cout<<ans;
return0;
}

3.2 编程题 2(末班车)

题解|GESP2026年9月C++八级真题解析-第18张图片-四季读书网

分析

到达车站后没有必要等待。若到达时间为 ,一条线路的末班车时间为 ,只要 ,就可以在第  分钟立即乘车。

另外,如果第  分钟从某站出发能够到达终点,那么更早出发也一定可以,因为可以先等待到第  分钟。

所以,对于任意起点和终点,只需要求出一个值最晚什么时候出发还能到达终点

部分分

对于  的数据。对于每一组询问 ,设  表示第  分钟从  出发到达  的最早时间。

初始时 ,对于线路 ,如果到达  时还没有错过末班车,即  就可以立即乘车,并进行转移 

直接使用 Dijkstra 算法。每组询问的时间复杂度为 

满分

此时不能每组询问单独运行 Dijkstra,但是车站数量只有 ,可以分别固定每个终点进行预处理。

设对于终点 ,定义  表示为了到达 ,最晚可以在什么时刻从  出发。

对于一条路线 ,如果要通过这条线路从  前往终点 ,出发时间  需要满足:

  1. 没有错过该线路的末班车,
  2. 到达  时,还来得及继续前往 

因此,通过这条线路时,从  出发的最晚时间为 

我们需要枚举  的所有出边,取最大值,

初始边界 ,表示已经位于终点时,不受出发时间限制。

转移需要用所有的  去更新 ,方向与原图相反。因此,我们对每条原图线路 ,可以在反图中保存一条从  指向  的边。固定终点  后:

固定终点  后:

  1. 令 
  2. 将  放入大根堆;
  3. 每次取出当前  最大的车站 
  4. 枚举原图中所有指向  的线路 (也就是反图中所有  的邻接点);
  5. 用  更新 

使用大根堆是因为我们要最大化最晚出发时间。

又因为 ,所以一次转移得到的时间满足 

沿着一条路线从起点走向终点时,允许的最晚时间会严格增大。因此从终点反向计算时,应该优先确定较大的值,大根堆正好满足这个顺序。这种做法可以看成反向求最晚出发时间的 Dijkstra。

综上, 对于每次询问 ,若  则第  分钟从  出发能够到达 ,输出 Yes;否则输出 No

每个终点运行一次大根堆 Dijkstra,共有  个终点 。每组询问的复杂度为 ,所以总时间复杂度为 

代码

#include<bits/stdc++.h>
usingnamespacestd;

using ll = longlong;
constint maxn = 505, inf = 1e9;
int dis[maxn], ans[maxn][maxn], n, m, q;
bool vis[maxn];

structedg {
int v, l, t;
};
vector<edg> g[maxn];

structnode {
int id, dis;
booloperator < (const node & rhs) const { // dis 大的先出队
return dis < rhs.dis;
    }
};

// 固定终点 target
// dis[u] 表示为了到达 target,最晚可以几点从 u 出发
voiddijkstra(int target)
memset(dis, -1sizeof(dis));
memset(vis, falsesizeof(vis));
    dis[target] = inf;
    priority_queue<node> pq;
    pq.push({target, dis[target]});
while(!pq.empty()) {
auto [u, d] = pq.top(); pq.pop();
if(vis[u]) continue;
        vis[u] = true;
for(auto [v, l, t]: g[u]) {
int ndis = min(l, dis[u] - t); // 原图有 v -> u 的线路
if(!vis[v] && ndis > dis[v]) {
                dis[v] = ndis;
                pq.push({v, dis[v]});
            }
        }
    }
}

intmain(){
cin>>n>>m>>q;
while(m--) {
int u, v, l, t;
cin>>u>>v>>l>>t;
        g[v].push_back({u, l, t}); // 建立反图
    }
for(int v = 1; v <= n; ++v) { // 固定每个终点的最晚出发时间
        dijkstra(v);
for(int u = 1; u <= n; ++u) ans[v][u] = dis[u];
    }
while(q--) {
int x, y, s;
cin>>x>>y>>s;
if(s <= ans[y][x]) cout<<"Yes\n";
elsecout<<"No\n";
    }
return0;
}

如果你喜欢这类赛事真题解析文章,欢迎点赞、转发、收藏,让更多人看到这份真诚的分享!

欢迎点击下方名片关注

抱歉,评论功能暂时关闭!