2025年北京市海淀区信息奥赛真题解析(小学组)

​欢迎大家订阅我的专栏:算法题解: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 n1 个好朋友,请你确定陶陶要最少要行走的总距离。

【输入】

第一行包含两个整数 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 xN,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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值