欢迎大家订阅我的专栏:算法题解:C++与Python实现!
本专栏旨在帮助大家从基础到进阶 ,逐步提升编程能力,助力信息学竞赛备战!
专栏特色
1.经典算法练习:根据信息学竞赛大纲,精心挑选经典算法题目,提供清晰的代码实现与详细指导,帮助您夯实算法基础。
2.系统化学习路径:按照算法类别和难度分级,从基础到进阶,循序渐进,帮助您全面提升编程能力与算法思维。
适合人群:
- 准备参加蓝桥杯、GESP、CSP-J、CSP-S等信息学竞赛的学生
- 希望系统学习C++/Python编程的初学者
- 想要提升算法与编程能力的编程爱好者
T1 硬币质量
【题目来源】
洛谷:B4237 [海淀区小学组 2025] 硬币重量 - 洛谷
【题目描述】
有三枚硬币,分别用
A
,
B
,
C
A, B, C
A,B,C 表示,两两重量互不相同。一种称量工具,每次称量,既能称量出一个物体的重量,也能直观地确定两个物体谁轻谁重。现将它们两两放在这种称量工具上比较它们的大小,并给出三次比较的结果,每个结果都以 > 和 < 的形式呈现。例如,如果硬币
A
A
A 比硬币
B
B
B 轻,则称重比较的结果表示为 A < B
。你的任务是根据给出的三个比较结果,将三枚硬币按它们的重量从小到大的顺序输出。如果给定的大小关系出现排序矛盾,则输出 Impossible
。
【输入】
第一行仅有一个正整数 T T T,表示测试数据的组数,对于每组测试数据包含三行,每行给出一个称重比较的结果。
【输出】
依次给出
T
T
T 组测试数据的结果,每组测试数据仅有一行,如果给出的三个比较结果,无法比较出三枚硬币重量的大小(结果相互矛盾),则输出 Impossible
,否则输出仅有三个特定字符的字符串,字符串中的字母从左到右代表的硬币重量从小到大。
【输入样例】
2
A>B
C<B
A>C
A<B
B>C
C>A
【输出样例】
CBA
ACB
【算法标签】
《海淀区比赛 硬币重量》 #北京# #模拟# #字符串# #小学科创活动# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int main()
{
int T;
cin >> T; // 输入测试用例的数量 T
while (T--) // 处理每个测试用例
{
int a = 0, b = 0, c = 0; // 初始化变量 a、b、c,分别表示 A、B、C 的得分
// 输入 3 个比较关系
for (int i = 1; i <= 3; i++)
{
string s;
cin >> s; // 输入一个比较关系字符串
// 根据比较关系更新 a、b、c 的得分
if (s[0] == 'A' && s[1] == '>') a++; // A > X,A 得分加 1
else if (s[0] == 'B' && s[1] == '>') b++; // B > X,B 得分加 1
else if (s[0] == 'C' && s[1] == '>') c++; // C > X,C 得分加 1
else if (s[2] == 'A' && s[1] == '<') a++; // X < A,A 得分加 1
else if (s[2] == 'B' && s[1] == '<') b++; // X < B,B 得分加 1
else if (s[2] == 'C' && s[1] == '<') c++; // X < C,C 得分加 1
}
// 根据 a、b、c 的得分判断 A、B、C 的大小关系
if (a < b && b < c) cout << "ABC" << endl; // A < B < C
else if (a < c && c < b) cout << "ACB" << endl; // A < C < B
else if (b < a && a < c) cout << "BAC" << endl; // B < A < C
else if (b < c && c < a) cout << "BCA" << endl; // B < C < A
else if (c < a && a < b) cout << "CAB" << endl; // C < A < B
else if (c < b && b < a) cout << "CBA" << endl; // C < B < A
else cout << "Impossible" << endl; // 如果无法确定大小关系,输出 "Impossible"
}
return 0;
}
【运行结果】
2
A>B
C<B
A>C
CBA
A<B
B>C
C>A
ACB
T2 分数方程
【题目来源】
洛谷:B4238 [海淀区小学组 2025] 分数方程 - 洛谷
【题目描述】
给定一个正整数 n n n,请找出一组互不相等的正整数 x , y , z x,y,z x,y,z,使得 1 x + 1 y + 1 z = 2 n \frac{1}{x}+\frac{1}{y}+\frac{1}{z}=\frac{2}{n} x1+y1+z1=n2 成立。
【输入】
仅有一个正整数 n n n。
【输出】
如果能够找到一组符合题目要求的三个数,则输出一行,包含三个整数 x , y , z x,y,z x,y,z,两两之间用空格分隔,否则输出 − 1 −1 −1。本题可能有多组解,输出任意一组均被视作正确(请注意:洛谷的在线 IDE 模式无法判断多组可能解,可能会误判答案错误)。
【输入样例】
3
【输出样例】
2 7 42
【算法标签】
《海淀区比赛 分数方程》 #北京# #小学科创活动# #2025# #Special Judge#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // 定义变量 n,表示输入的数
int main()
{
cin >> n; // 输入 n
int x = n; // 定义 x,初始化为 n
int y = n * (n + 1); // 定义 y,计算 n * (n + 1)
int z = n + 1; // 定义 z,初始化为 n + 1
cout << x << " " << y << " " << z << endl; // 输出 x、y、z
return 0;
}
【运行结果】
3
3 12 4
T3 拜访朋友
【题目来源】
洛谷:B4239 [海淀区小学组 2025] 拜访朋友 - 洛谷
【题目描述】
陶陶有 n n n 个好朋友,他们的住所都分布在同一条笔直的街道旁,如果把这条街道看作一个数轴,选定一个点作为坐标原点(坐标为 0 0 0),则这 n n n 个好朋友的住所的坐标分别为 x 1 , x 2 , … , x n x_1,x_2,…,x_n x1,x2,…,xn。一天,陶陶要去朋友们的住所去拜访朋友们,陶陶初始位置的坐标为 x 0 x_0 x0,他希望至少拜访到 n − 1 n−1 n−1 个好朋友,请你确定陶陶要最少要行走的总距离。
【输入】
第一行包含两个整数 n n n 和 x 0 x_0 x0,第二行包含 n n n 个整数 x 1 , x 2 , … , x n x_1,x_2,…,x_n x1,x2,…,xn。
【输出】
仅有一个正整数,表示最小的总行走距离。
【输入样例】
3 10
1 7 12
【输出样例】
7
【算法标签】
《海淀区比赛 拜访朋友》 #北京# #贪心# #排序# #小学科创活动# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 定义常量 N,表示数组的最大长度
int n, a0; // n 表示数组的长度,a0 表示初始位置
int a[N]; // 数组 a 用于存储输入的 n 个数
int main()
{
cin >> n >> a0; // 输入数组长度 n 和初始位置 a0
for (int i = 1; i <= n; i++) // 输入数组 a 的 n 个元素
{
cin >> a[i];
}
if (n == 1) // 如果数组长度为 1,直接输出 0
{
cout << 0 << endl;
return 0;
}
sort(a + 1, a + n + 1); // 对数组 a 进行升序排序
// 计算四种可能的移动距离
int d1 = abs(a[n] - a0) + (a[n] - a[2]); // 移动到最右端,再覆盖到第二小
int d2 = abs(a[n - 1] - a0) + (a[n - 1] - a[1]); // 移动到次右端,再覆盖到最小
int d3 = abs(a0 - a[1]) + (a[n - 1] - a[1]); // 移动到最左端,再覆盖到次小
int d4 = abs(a0 - a[2]) + (a[n] - a[2]); // 移动到第二小,再覆盖到最右端
// 输出四种距离中的最小值
cout << min(d1, min(d2, min(d3, d4))) << endl;
return 0;
}
【运行结果】
3 10
1 7 12
7
T4 最短字符串
【题目来源】
洛谷:B4240 [海淀区小学组 2025] 最短字符串 - 洛谷
【题目描述】
给定一个仅由大小写字母构成的长度为 n n n 的字符串 S S S,求字符串 S S S 的一个子串 T T T,使得字符串 T T T 中包含字符串 S S S 中所有种类的字母(区分大小写),输出子串 T T T 的最小长度。例如,如果 S = a a B C C e S=aaBCCe S=aaBCCe,则 S S S 中包含的不同种类的字母有 a , B , C , e a,B,C,e a,B,C,e,要子串中包含全部的这四类字母,则子串的索引区间为 [ 2 , 6 ] [2,6] [2,6],即 S S S 中的第 2 2 2 个字符到第 6 6 6 个字符,即字符串 a B C C e aBCCe aBCCe。
【输入】
第一行仅有一个整数 n n n,第二行包含一个符合题目要求的长度为 n n n 的字符串 S S S。
【输出】
仅有一个不超过 n n n 的正整数,表示符合题目要求的子串的最小长度。
【输入样例】
3
AaA
【输出样例】
2
【算法标签】
《海淀区比赛 最短字符串》 #北京# #双指针,two-pointer# #小学科创活动# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 160; // 定义常量 N,表示字符集的大小(ASCII 字符)
int n; // 定义变量 n,表示字符串的长度
string s; // 定义字符串 s,表示输入的字符串
char a[N]; // 定义数组 a,用于记录字符的出现次数
int ans; // 定义变量 ans,用于记录最小窗口的长度
int main()
{
cin >> n >> s; // 输入字符串长度 n 和字符串 s
int l = 0, r = 0; // 定义双指针 l 和 r,表示滑动窗口的左右边界
while (r < n) // 遍历字符串
{
if (a[s[r]] == 0) ans = r - l + 1; // 如果当前字符是新字符,更新窗口长度
a[s[r]]++; // 记录当前字符的出现次数
// 移动左指针,缩小窗口
while (l < r)
{
if (a[s[l]] == 1) break; // 如果左指针指向的字符只出现一次,停止移动
a[s[l]]--; // 减少左指针指向字符的出现次数
l++; // 移动左指针
}
ans = min(ans, r - l + 1); // 更新最小窗口长度
r++; // 移动右指针
}
cout << ans << endl; // 输出最小窗口长度
return 0;
}
【运行结果】
3
AaA
2
T5 统计数对
【题目来源】
洛谷:B4241 [海淀区小学组 2025] 统计数对 - 洛谷
【题目描述】
陶陶是一个计算机爱好者,对二进制数有着特别的喜好,遇到各种各样的数据,他总能找到跟 2 2 2 的整数次幂的关系。现在,他获得了一个长度为 n n n 的数列 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an,他发现其中有些元素的和恰好是 2 2 2 的整数次幂。对于给定的 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an,你的任务是统计有多少个数对 ( i , j ) (i,j) (i,j) 满足 a i + a j = 2 x a_i+a_j=2^x ai+aj=2x,其中 x ∈ N ∗ , i < j x\in \mathbb{N}^∗,i<j x∈N∗,i<j,这里 N ∗ \mathbb{N}^∗ N∗ 表示正整数集合。
【输入】
第一行包含一个整数 n n n,第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an。
【输出】
仅有一个正整数,表示满足 a i + a j a_i+a_j ai+aj 是 2 2 2 的整数次幂的数对 ( i , j ) (i,j) (i,j) 的个数。
【输入样例】
4
7 3 2 1
【输出样例】
2
【算法标签】
《海淀区比赛 统计数对》 #北京# #二分# #哈希hashing# #小学科创活动# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
#define int long long // 定义宏,将 int 替换为 long long,方便处理大整数
const int N = 100005; // 定义常量 N,表示数组的最大长度
int n; // n 表示数组的长度
int a[N]; // 数组 a 用于存储输入的 n 个数
map<int, int> mp; // 定义 map,用于记录数组中每个数的出现次数
signed main()
{
cin >> n; // 输入数组长度 n
for (int i = 1; i <= n; i++) // 输入数组 a 的 n 个元素
{
cin >> a[i];
mp[a[i]]++; // 记录每个数的出现次数
}
int ans = 0; // 定义变量 ans,用于记录满足条件的对数
for (int i = 1; i < n; i++) // 遍历数组中的每个数
{
mp[a[i]]--; // 将当前数从 map 中移除,避免重复计数
// 检查是否存在另一个数,使得两者之和是 2 的幂
for (int j = 0; j <= 30; j++) // 遍历 2^0 到 2^30
{
int target = (1 << j) - a[i]; // 计算目标值
if (mp.count(target)) // 如果目标值存在于 map 中
{
ans += mp[target]; // 更新满足条件的对数
}
}
}
cout << ans << endl; // 输出满足条件的对数
return 0;
}
【运行结果】
4
7 3 2 1
2
T6 蜂窝网络
【题目来源】
洛谷:B4242 [海淀区小学组 2025] 蜂窝网络 - 洛谷
【题目描述】
有 n n n 个城市编号从 1 1 1 到 n n n 和 m m m 个信号发射塔编号从 1 1 1 到 m m m 都分布在一条直线上,如果选择直线上某个点的坐标为 0 0 0,则这 n n n 个城市的坐标可以描述为 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an,这 m m m 个信号发射塔的坐标可描述为 b 1 , b 2 , … , b m b_1,b_2,…,b_m b1,b2,…,bm。每个信号发射塔能为它左右不超过 r r r 的距离以内的城市提供上网流量,你的任务是确定 r r r 最小为多少时才能保证所有城市都有网络信号?
【输入】
第一行包含两个正整数 n n n 和 m m m,分别表示城市的个数和信号发射塔的个数,第二行包含 n n n 个整数 a 1 , a 2 , … , a n a_1,a_2,…,a_n a1,a2,…,an,依次为每个城市的位置坐标,第三行包含 m 个整数 b 1 , b 2 , … , b m b_1,b_2,…,b_m b1,b2,…,bm,依次为每个信号发射塔的位置坐标。允许多个城市或信号发射塔位置相同。
【输出】
仅有一个整数,能使所有城市都有网络信号覆盖的最小的 r r r 值。
【输入样例】
3 2
-2 2 4
-3 0
【输出样例】
4
【算法标签】
《海淀区比赛 蜂窝网络》 #北京# #二分# #小学科创活动# #2025#
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100005; // 定义常量 N,表示数组的最大长度
int n, m; // n 表示数组 a 的长度,m 表示数组 b 的长度
int a[N], b[N]; // 数组 a 和 b 用于存储输入的数据
int main()
{
cin >> n >> m; // 输入数组 a 的长度 n 和数组 b 的长度 m
// 输入数组 a
for (int i = 1; i <= n; i++)
cin >> a[i];
// 输入数组 b
for (int i = 1; i <= m; i++)
cin >> b[i];
// 对数组 a 和 b 进行升序排序
sort(a + 1, a + n + 1);
sort(b + 1, b + m + 1);
int ans = -1e9; // 初始化答案为负无穷
// 遍历数组 a 中的每个元素
for (int i = 1; i <= n; i++)
{
int d = 1e9; // 初始化当前元素 a[i] 的最小距离为无穷大
// 使用 lower_bound 在数组 b 中查找第一个大于等于 a[i] 的元素的位置
int idx = lower_bound(b + 1, b + m + 1, a[i]) - b;
// 检查找到的位置是否在数组 b 的范围内
if (idx >= 1 && idx <= m)
d = min(d, abs(b[idx] - a[i])); // 更新最小距离
// 检查前一个位置是否在数组 b 的范围内
if (idx - 1 >= 1)
d = min(d, abs(b[idx - 1] - a[i])); // 更新最小距离
ans = max(ans, d); // 更新全局答案
}
cout << ans << endl; // 输出答案
return 0;
}
【运行结果】
3 2
-2 2 4
-3 0
4