GESP认证C++编程真题解析 | 202503 七级
欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
附上汇总帖:GESP认证C++编程真题解析 | 汇总
编程题
P11964 图上移动
【题目来源】
洛谷:P11964 [GESP202503 七级] 图上移动 - 洛谷 (luogu.com.cn)
【题目描述】
小 A 有一张包含 \(n\) 个结点与 \(m\) 条边的无向图,结点以 \(1,2,…,n\) 标号。小 A 会从图上选择一个结点作为起点,每一步移动到某个与当前小 A 所在结点相邻的结点。对于每个结点 \(i (1≤i≤n)\),小 A 想知道从结点 \(i\) 出发恰好移动 \(1,2,…,k\) 步之后,小 A 可能会位于哪些结点。由于满足条件的结点可能有很多,你只需要求出这些结点的数量。
【输入】
第一行,三个正整数 \(n,m,k\),分别表示无向图的结点数与边数,最多移动的步数。
接下来 \(m\) 行,每行两个正整数 \(u_i,v_i\),表示图中的一条连接结点 \(u_i\) 与 \(v_i\) 的无向边。
【输出】
共 \(n\) 行,第 \(i\) 行 \((1≤i≤n)\) 包含 \(k\) 个整数,第 \(j\) 个整数 \((1≤j≤k)\) 表示从结点 \(i\) 出发恰好移动 \(j\) 步之后可能位置的结点数量。
【输入样例】
4 4 3
1 2
1 3
2 3
3 4
【输出样例】
2 4 4
2 4 4
3 3 4
1 3 3
【算法标签】
《洛谷 P11964 图上移动》 #动态规划DP# #GESP# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 505, K = 25; // 定义最大节点数N和最大步数K
int n, m, k; // n: 节点数,m: 边数,k: 最大步数
int vis[N][K]; // 记录节点u在step步内是否能被访问到
int h[N], e[N * 2], ne[N * 2], idx; // 邻接表存储图
// 添加边到邻接表
void add(int a, int b) {
e[idx] = b, ne[idx] = h[a], h[a] = idx++;
}
// 深度优先搜索
void dfs(int u, int step) {
if (vis[u][step]) return; // 如果当前状态已访问,直接返回
vis[u][step] = 1; // 标记当前状态为已访问
if (step == k) return; // 如果达到最大步数,停止递归
// 遍历所有邻居节点
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
dfs(j, step + 1); // 递归访问邻居节点,步数加1
}
}
int main() {
cin >> n >> m >> k; // 输入节点数、边数和最大步数
memset(h, -1, sizeof h); // 初始化邻接表
// 构建图的邻接表
for (int i = 1; i <= m; i++) {
int a, b;
cin >> a >> b;
add(a, b), add(b, a); // 无向图,添加双向边
}
// 对每个节点进行DFS,统计在1到k步内能到达的节点数
for (int i = 1; i <= n; i++) {
memset(vis, 0, sizeof vis); // 初始化访问数组
dfs(i, 0); // 从节点i开始DFS,初始步数为0
// 输出从节点i出发,在1到k步内能到达的节点数
for (int j = 1; j <= k; j++) {
int res = 0;
for (int kk = 1; kk <= n; kk++) {
res += vis[kk][j]; // 统计在j步内能到达的节点数
}
cout << res << " ";
}
cout << endl;
}
return 0;
}
【运行结果】
4 4 3
1 2
1 3
2 3
3 4
2 4 4
2 4 4
3 3 4
1 3 3
P11965 等价消除
【题目来源】
洛谷:P11965 [GESP202503 七级] 等价消除 - 洛谷 (luogu.com.cn)
【题目描述】
小 A 有一个仅包含小写英文字母的字符串 \(S\)。
对于一个字符串,如果能通过每次删去其中两个相同字符的方式,将这个字符串变为空串,那么称这个字符串是可以被等价消除的。
小 A 想知道 \(S\) 有多少子串是可以被等价消除的。
一个字符串 \(S'\) 是 \(S\) 的子串,当且仅当删去 \(S\) 的某个可以为空的前缀和某个可以为空的后缀之后,可以得到 \(S'\)。
【输入】
第一行,一个正整数 \(|S|\),表示字符串 \(S\) 的长度。
第二行,一个仅包含小写英文字母的字符串 \(S\)。
【输出】
一行,一个整数,表示答案。
【输入样例】
7
aaaaabb
【输出样例】
9
【算法标签】
《洛谷 P11965 等价消除》 #前缀和# #位运算# #GESP# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 定义宏,将int替换为long long类型
const int N = 2e5 + 5; // 定义最大字符数
int n, x, ans; // n: 字符串长度,x: 当前异或值,ans: 结果计数
char a[N]; // 存储输入的字符串
map<int, int> mp; // 哈希表,记录异或值出现的次数
signed main() {
cin >> n; // 输入字符串长度
cin >> a; // 输入字符串
mp[0] = 1; // 初始化:空字符串的异或值为0,出现1次
for (int i = 0; i < n; i++) {
// 计算当前字符对应的位,并更新异或值
x ^= (1 << (a[i] - 'a'));
// 如果当前异或值之前出现过,则存在满足条件的子串
ans += mp[x];
// 更新当前异或值的出现次数
mp[x]++;
}
cout << ans << endl; // 输出满足条件的子串数量
return 0;
}
【运行结果】
7
aaaaabb
9

浙公网安备 33010602011771号