GESP认证C++编程真题解析 | 202312 六级
欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
附上汇总帖:GESP认证C++编程真题解析 | 汇总
编程题
P10108 闯关游戏
【题目来源】
洛谷:[P10108 GESP202312 六级] 闯关游戏 - 洛谷
【题目描述】
你来到了一个闯关游戏。
这个游戏总共有 \(N\) 关,每关都有 \(M\) 个通道,你需要选择一个通道并通往后续关卡。其中,第 \(i\) 个通道可以让你前进 \(a_i\) 关,也就是说,如果你现在在第 \(x\) 关,那么选择第 \(i\) 个通道后,你将直接来到第 \(x+a_i\) 关(特别地,如果 \(x + a_i \geq N\),那么你就通关了)。此外,当你顺利离开第 \(s\) 关时,你还将获得 \(b_s\) 分。
游戏开始时,你在第 \(0\) 关。请问,你通关时最多能获得多少总分。
【输入】
第一行两个整数 \(N\),\(M\),分别表示关卡数量和每关的通道数量。
接下来一行 \(M\) 个用单个空格隔开的整数 \(a_0,a_1\cdots,a_{M-1}\)。保证 \(1\le a_i \le N\)。
接下来一行 \(N\) 个用单个空格隔开的整数 \(b_0,b_1\cdots,b_{N-1}\)。保证 \(|b_i|\le 10^5\)。
【输出】
一行一个整数,表示你通关时最多能够获得的分数。
【输入样例】
6 2
2 3
1 0 30 100 30 30
【输出样例】
131
【算法标签】
《洛谷 P10108 闯关游戏》 #动态规划DP# #GESP# #2023#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 200005; // 最大数组长度
int n, m; // n: 天数, m: 药材种类数
int maxn = -1; // 最大的生长天数
int a[N], b[N]; // a: 药材生长天数, b: 每天可种植的药材价值
int dp[N]; // dp[i]: 在第i天结束时的最大总价值
int main()
{
// 输入药材种类数和总天数
cin >> m >> n;
// 输入每种药材的生长天数
for (int i = 1; i <= m; i++)
{
cin >> a[i];
maxn = max(maxn, a[i]); // 记录最长的生长周期
}
// 输入每天可种植的药材价值
for (int i = 1; i <= n; i++)
{
cin >> b[i];
}
// 初始化dp数组为极小值
memset(dp, -0x3f, sizeof(dp));
dp[1] = 0; // 第1天开始时,总价值为0
// 动态规划
// 注意:这里循环到n+maxn,因为药材可能在n天后成熟
for (int i = 1; i <= n + maxn; i++)
{
for (int j = 1; j <= m; j++)
{
// 如果i-a[j]天是有效的(≥1)
if (i - a[j] >= 1)
{
// 状态转移:在第i-a[j]天种植,在第i天收获
dp[i] = max(dp[i], dp[i - a[j]] + b[i - a[j]]);
}
}
}
// 调试输出
// for (int i=1; i<=n+maxn; i++)
// cout << dp[i] << " ";
// cout << endl;
// 寻找最大价值
// 只需要考虑n天之后到n+maxn天之间的最大值
int ans = -1e9;
for (int i = n + 1; i <= n + maxn; i++)
{
ans = max(ans, dp[i]);
}
// 输出结果
cout << ans << endl;
return 0;
}
【运行结果】
6 2
2 3
1 0 30 100 30 30
131
P10109 工作沟通
【题目来源】
洛谷:[P10109 GESP202312 六级] 工作沟通 - 洛谷
【题目描述】
某公司有 \(N\) 名员工,编号从 \(0\) 至 \(N-1\)。其中,除了 \(0\) 号员工是老板,其余每名员工都有一个直接领导。我们假设编号为 \(i\) 的员工的直接领导是 \(f_i\)。
该公司有严格的管理制度,每位员工只能受到本人或直接领导或间接领导的管理。具体来说,规定员工 \(x\) 可以管理员工 \(y\),当且仅当 \(x=y\),或 \(x=f_y\),或 \(x\) 可以管理 \(f_y\)。特别地,\(0\) 号员工老板只能自我管理,无法由其他任何员工管理。
现在,有一些同事要开展合作,他们希望找到一位同事来主持这场合作,这位同事必须能够管理参与合作的所有同事。如果有多名满足这一条件的员工,他们希望找到编号最大的员工。你能帮帮他们吗?
【输入】
第一行一个整数 \(N\),表示员工的数量。
第二行 \(N - 1\) 个用空格隔开的正整数,依次为 \(f_1,f_2,\dots f_{N−1}\)。
第三行一个整数 \(Q\),表示共有 \(Q\) 场合作需要安排。
接下来 \(Q\) 行,每行描述一场合作:开头是一个整数 \(m\)(\(2 \le m \le N\)),表示参与本次合作的员工数量;接着是 \(m\) 个整数,依次表示参与本次合作的员工编号(保证编号合法且不重复)。
保证公司结构合法,即不存在任意一名员工,其本人是自己的直接或间接领导。
【输出】
输出 \(Q\) 行,每行一个整数,依次为每场合作的主持人选。
【输入样例】
5
0 0 2 2
3
2 3 4
3 2 3 4
2 1 4
【输出样例】
2
2
0
【算法标签】
《洛谷 P10109 工作沟通》 #图论# #图遍历# #GESP# #2023#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 305; // 最大节点数
int n, q; // n: 节点数, q: 查询次数
vector<int> g[N]; // 邻接表存储树
bool st[N]; // 访问标记数组
// 深度优先搜索,标记从u出发能到达的所有节点
void dfs(int u)
{
st[u] = 1; // 标记当前节点
for (int i = 0; i < g[u].size(); i++)
{
st[g[u][i]] = 1; // 标记子节点
dfs(g[u][i]); // 递归遍历
}
}
int main()
{
// 输入节点数
cin >> n;
// 输入树的n-1条边
for (int i = 1; i < n; i++)
{
int x;
cin >> x; // 节点i的父节点
g[x].push_back(i); // 建立从父节点x到子节点i的边
}
// 输入查询次数
cin >> q;
// 处理每个查询
while (q--)
{
int m; // 查询中包含的节点数
cin >> m;
vector<int> ve; // 存储查询节点
// 输入查询节点
for (int i = 1; i <= m; i++)
{
int x;
cin >> x;
ve.push_back(x);
}
// 从大到小遍历节点编号
for (int i = n - 1; i >= 0; i--)
{
// 重置访问标记
memset(st, 0, sizeof(st));
// 从节点i开始DFS,标记所有可达节点
dfs(i);
// 检查是否所有查询节点都被标记
bool flag = 1;
for (int j = 0; j < ve.size(); j++)
{
if (st[ve[j]] == false) // 有节点未标记
{
flag = 0;
break;
}
}
// 如果所有查询节点都在i的子树中
if (flag)
{
cout << i << endl; // 输出当前节点编号
break; // 找到答案,退出循环
}
}
}
return 0;
}
【运行结果】
5
0 0 2 2
3
2 3 4
2
3 2 3 4
2
2 1 4
0

浙公网安备 33010602011771号