夜雨聆风学习资料网

ARTICLE · 1015479

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

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

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

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

【答案】: C。

【解析】:5 & 3 = 15 | 3 = 7

【答案】: D。

【解析】:

  • A 选项错误,pow(2, 3) 的返回值类型为 double
  • B 选项错误,sin(30) 的参数  表述弧度。
  • C 选项错误,sqrt(4) 的返回值为 double 类型。
  • D 选项正确。

【答案】: C。

【解析】: 构造哈夫曼树,每次选两个出现次数少的节点合并。

【答案】: B。

【解析】: 可以递推,也可以用组合数求解, 的格点,会形成  的网格,总共需要走  步,其中有  步往下走,方案数就是 

【答案】: A。

【解析】: 最坏情况会形成一条链,时间复杂度为 ,平均情况为 

【答案】: B。

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

【答案】: A。

【解析】: BFS每次往外扩展一层,dist[i] 表示到达 i 的最少边数。

【答案】: D。

【解析】: DFS或者BFS搜索网格。

【答案】: C。

【解析】:

  • A 选项错误,哈希是一个基于概率的算法,不可完全避免冲突。
  • B 选项错误,在大量元素冲突的时候,查找一个元素可能是  的。
  • C 选项正确。
  • D 选项错误,哈希冲突时,查找速度与表中个数有关。

【答案】: B。

【解析】: 参数是引用,共享同一个地址,函数内部改变了,外部的实参 a 也会改变。

【答案】: A。

【解析】: 最长公共子序列模板。

【答案】: D。

【解析】: 只放入了一个  的物品,价值为 

【答案】: D。

【解析】: 快速排序是不稳定的排序。

【答案】: B。

【解析】: 内层循环是调和级数,总时间复杂度为 

【答案】: C。

【解析】:p 是  的地址,*(p + 3) 就是 a[4]

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

2.1 判断题题面

2.2 判断题解析

第 1 题exp 返回 double 类型。

第 2 题。删除一个元素后不能直接将该位置置空,否则会破坏后续查找的正确性。

第 3 题。通常情况下频率越高的结点离根越近,但“出现次数更多的叶子结点,其深度总是更小”这一表述过于绝对,存在反例。例如  构造哈夫曼树。

第 4 题。一条边提供一个入度和一个出度。

第 5 题。显然正确。

第 6 题。快排最坏情况下会退化为 

第 7 题。滚动数组,倒序枚举背包容量。

第 8 题。邻接表只存了实际存在的边,遍历一个顶点的邻接点时,不需要遍历所有顶点。

第 9 题。完全二叉树的性质。

第 10 题arr 和 &arr[0] 的值(地址)相同,但它们在C/C++语言中并不总是等价。两者的关键区别在于类型和在特定运算符下的行为。

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

3.1 编程题 1(必经之路)

分析

这道题的核心是:判断删除某个点后,是否还存在一条“原合法起点到原合法终点”的路径。

如果还存在,说明可以绕开这个点,它就不是必经点;如果不存在,说明所有合法路径都必须经过它,它就是必经点。

设原图中的合法起点集合为 ,合法终点集合为 。对于每个结点 ,暂时禁止经过 ,然后从所有不等于  的合法起点同时进行 BFS 或 DFS:

  • 如果能到达某个不等于  的合法终点,则存在一条绕开  的路径;
  • 否则  是必经点。

这里有一个容易出错的地方:删除  后,不能重新计算合法起点和合法终点。合法起点、合法终点必须按照原图的入度和出度确定。

例如删除一个结点后,它的前驱可能变成出度为 ,但这个前驱并不是原题定义的合法终点,不能把它算进去。

时间复杂度为 ,可以接受。

代码

#include<bits/stdc++.h>usingnamespacestd;constint maxn = 1005;int in[maxn], out[maxn], n, m;bool ed[maxn], vis[maxn];vector<int> st, ans;vector<int> g[maxn];boolcheck(int ban)// 判断是否存在一条不经过ban的路径memset(vis, falsesizeof(vis));queue<int> q;for(int x: st) {if(x != ban) {            vis[x] = true;            q.push(x);        }    }while(!q.empty()) {int u = q.front(); q.pop();if(ed[u]) returntrue// 到达合法终点for(int v: g[u]) {if(v == ban || vis[v]) continue;            vis[v] = true;            q.push(v);        }    }returnfalse;}intmain(){cin>>n>>m;while(m--) {int u, v;cin>>u>>v;        g[u].push_back(v), g[v].push_back(u);        ++out[u], ++in[v];    }for(int i = 1; i <= n; ++i) {if(in[i] == 0) st.push_back(i);if(out[i] == 0) ed[i] = true;    }for(int i = 1; i <= n; ++i) {if(!check(i)) ans.push_back(i);    }cout<<ans.size()<<'\n';for(int x: ans) cout<<x<<" ";return0;}

3.2 编程题 2(括号序列)

分析

合法括号序列有两个必要条件:

  1. 从左到右扫描时,任意前缀中左括号数量不少于右括号数量。
  2. 扫描结束后,左右括号数量相等。

定义括号余额 。扫描过程中余额不能小于 ,最后必须等于 

设  表示处理到第  个字符,目前括号余额为  的方案数。

对于每一个字符,我们都有两种选择:

  1. 不选,此时直接继承 
  2. 选,就要看当前是 ( 还是 ),如果是 (,那么  应该来源于 ;如果是 ) 来源于 
    • 对于选的转移,还需要判断前缀括号序列中括号是否合法,即左括号数量是否不少于有括号数量

时间复杂度为 

代码

#include<bits/stdc++.h>usingnamespacestd;constint maxn = 2005, mod = 1e9;int dp[maxn][maxn], n;string s;intmain(){cin>>n>>s;    s = " " + s;    dp[0][0] = 1;for(int i = 1; i <= n; ++i) {for(int j = 0; j <= i; ++j) {            dp[i][j] = dp[i - 1][j];if(s[i] == '(' && j > 0) {                dp[i][j] = (dp[i][j] + dp[i - 1][j - 1]) % mod;            } elseif(s[i] == ')' && i - 1 >= j + 1) {                dp[i][j] = (dp[i][j] + dp[i - 1][j + 1]) % mod;            }        }    }cout<<dp[n][0];return0;}

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

欢迎点击下方名片关注

相关学习资料

返回首页浏览学习资料