学而思编程每周练习赛 | 2026年春第1周

附上学而思公众号链接:学而思编程每周练习赛-第01周-习题视频讲解与试题分析

语言基础组

演讲比赛

【题目来源】

学而思编程:演讲比赛

【题目描述】

小X的学校组织了一场演讲比赛,由 \(n\) 位评委对参赛选手进行打分。打分规则是去掉 \(n\) 位评委中最高得分和最低得分后,计算出剩余 \(n−2\) 位评委分数的平均值(保留两位小数)作为最后得分。

小X同学也积极参加了本次演讲比赛,请你帮小X计算一下他的最后得分。

【输入】

输入有 \(2\) 行,第 \(1\) 行,一个正整数 \(n\),表示有 \(n\) 位评委。

\(2\) 行,有 \(n\) 个正整数 \(p_i\),表示每一位评委的打分。

【输出】

输出一个数字,表示小X的最后得分,保留两位小数

【输入样例】

8
50 90 55 78 52 68 66 93

【输出样例】

68.17

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    // 输入数据个数n
    int n;
    cin >> n;
    
    // 初始化最大值、最小值和总和
    int mx = 0;      // 存储最大值,初始设为最小值
    int mn = 100;    // 存储最小值,初始设为最大值
    int sum = 0;     // 存储所有数的总和

    // 循环读取n个数
    for (int i = 1; i <= n; i++)
    {
        int p;
        cin >> p;    // 读取当前数
        
        // 累加到总和
        sum += p;
        
        // 更新最大值
        if (p > mx)
        {
            mx = p;
        }
        
        // 更新最小值
        if (p < mn)
        {
            mn = p;
        }
    }
    
    // 计算去掉一个最高分和一个最低分后的平均分
    // 注意:n-2是除数,因为去掉了两个数
    double avg = 1.0 * (sum - mx - mn) / (n - 2);
    
    // 输出结果,保留两位小数
    printf("%.2lf\n", avg);
    
    return 0;
}

【运行结果】

8
50 90 55 78 52 68 66 93
68.17

平均数

【题目来源】

学而思编程:平均数

【题目描述】

读取 \(4\) 个数字 \(N1,N2,N3,N4\),这 \(4\) 个数字都是保留 \(1\) 位小数的浮点数,对应于学生获得的 \(4\) 个分数。

\(4\) 个分数的权重分别为 \(2,3,4,1\),请你计算学生成绩的平均值 \(X\) 并输出 Media: X。其中,学生平均成绩\(=(2∗N1+3∗N2+4∗N3+N4)/10\)

接下来分为以下三种情况:

如果平均值为 \(7.0\) 或更高,则输出 Aluno aprovado.

如果平均值小于 \(5.0\),则输出 Aluno reprovado.

如果平均值大于等于 \(5.0\) 并且小于 \(7.0\),则输出 Aluno em exame.,并再读取一个数字 \(Y\),然后输出 Nota do exame: Y。接下来重新计算平均值 \(Z=(X+Y)/2\),如果 \(Z\) 大于或等于 \(5.0\),则输出 Aluno aprovado.,否则输出 Aluno reprovado.。最后输出 Media final: Z,表示学生的最终成绩。

【输入】

输入中包含四个浮点数,表示学生的四个成绩。

也有部分满足情况 \(3\) 的数据,多包含一个浮点数

【输出】

输出的结果均保留 \(1\) 位小数,具体形式参照题目描述和输出样例。

【输入样例】

2.0 4.0 7.5 8.0
6.4

【输出样例】

Media: 5.4
Aluno em exame.
Nota do exame: 6.4
Aluno aprovado.
Media final: 5.9

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    // 定义变量并输入四个成绩
    double a, b, c, d;
    cin >> a >> b >> c >> d;

    // 计算加权平均成绩(权重分别为2,3,4,1)
    double x = (2 * a + 3 * b + 4 * c + d) / 10;
    
    // 输出平均成绩,保留1位小数
    printf("Media: %.1lf\n", x);

    // 判断学生成绩状态
    if (x >= 7.0) 
    {
        // 平均分≥7.0,直接通过
        cout << "Aluno aprovado." << endl;
    } 
    else if (x < 5.0) 
    {
        // 平均分<5.0,直接不通过
        cout << "Aluno reprovado." << endl;
    } 
    else 
    {
        // 5.0≤平均分<7.0,需要补考
        cout << "Aluno em exame." << endl;
        
        // 输入补考成绩
        double y; 
        cin >> y;
        printf("Nota do exame: %.1lf\n", y);
        
        // 计算最终成绩(原成绩和补考成绩的平均)
        double z = (x + y) / 2;
        
        // 判断补考后是否通过
        if (z >= 5.0) 
        {
            cout << "Aluno aprovado." << endl;
        }
        else 
        {
            cout << "Aluno reprovado." << endl;
        }
        
        // 输出最终成绩
        printf("Media final: %.1lf\n", z);
    }
    
    return 0;
}

【运行结果】

2.0 4.0 7.5 8.0
Media: 5.4
Aluno em exame.
6.4
Nota do exame: 6.4
Aluno aprovado.
Media final: 5.9

蚂蚁

【题目来源】

学而思编程:蚂蚁

【题目描述】

\(n\) 蚂蚁在长度为 \(L\) 单位的木棍上,每只蚂蚁都有一个初始的位置和初始朝向(任意两只蚂蚁的初始位置不同),每只蚂蚁都以每秒一个单位的速度向前移动。其中一部分蚂蚁向左移动,其他蚂蚁向右移动。

当两只向不同方向移动的蚂蚁在某个点相遇时,它们会同时改变移动方向并继续移动。假设更改方向不会花费任何额外时间。

而当蚂蚁在某一时刻 \(t\) 到达木板的一端时,它立即从木板上掉下来,初始时刻 \(t=0\)。请你用编程实现:最后一只蚂蚁从木棍上掉下来的时刻。

【输入】

输入有 \(n+1\) 行,第 \(1\) 行两个正整数 \(n,L\);

\(2\) 行到第 \(n+1\) 行,每行两个整数 \(x_i,d_i\)\(x_i\) 表示第 \(i\) 只蚂蚁的初始位置,\(d_i\) 表示第 \(i\) 只蚂蚁的初始朝向,其中 \(d_i=0\) 表示第 \(i\) 只蚂蚁初始朝向向左,\(d_i=1\) 表示第 \(i\) 只蚂蚁初始朝向向右。

【输出】

输出一个整数 \(t\),最后一只蚂蚁从木棍上掉下来的时刻。

【输入样例】

4 4
0 1
1 1
3 0
4 0

【输出样例】

4

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    // 输入n(物品数量)和L(总长度)
    int n, L;
    cin >> n >> L;
    
    // 初始化最大距离ans为0
    int ans = 0;
    
    // 遍历每个物品
    for (int i = 1; i <= n; i++)
    {
        // 输入物品的位置x和方向d
        int x, d;
        cin >> x >> d;
        
        // 根据物品方向处理
        if (d == 0)
        {
            // 方向为0(向左):最大距离就是x本身
            if (x > ans)
            {
                ans = x;
            }
        }
        else
        {
            // 方向为1(向右):最大距离是L-x
            if (L - x > ans)
            {
                ans = L - x;
            }
        }
    }
    
    // 输出所有物品中的最大距离
    cout << ans;
    
    return 0;
}

【运行结果】

4 4
0 1
1 1
3 0
4 0
4

普及奠基组

三角形牧场

【题目来源】

学而思编程:三角形牧场

【题目描述】

Farmer John 想要给他的奶牛们建造一个三角形牧场。

\(N\) 个栅栏柱子分别位于农场的二维平面上不同的点 \((X_1,Y_1)\dots(X_N,Y_N)\)

他可以选择其中三个点组成三角形牧场,只要三角形有一条边与 \(x\) 轴平行,且有另一条边与 \(y\) 轴平行。

FJ 可以组成的合法三角形的最大面积多少 ?保证存在至少一个合法的三角形牧场。

【输入】

第一行包含 \(N\)

以下 \(N\) 行每行包含两个整数 \(X_i\)\(Y_i\),均在范围 \(-10^4\dots 10^4\) 之内,描述一个栅栏柱子的位置。

【输出】

由于面积不一定为整数,输出栅栏柱子可以围成的合法三角形的最大面积的两倍

【输入样例】

4
0 0
0 1
1 0
1 2

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int x[105], y[105];  // 存储n个点的x坐标和y坐标

int main()
{
    int n;
    cin >> n;  // 读入点的数量
    
    // 读入n个点的坐标
    for (int i = 1; i <= n; i++)
    {
        cin >> x[i] >> y[i];
    }
    
    int ans = 0;  // 初始化最大矩形面积为0
    
    // 三重循环枚举矩形的三个顶点
    for (int i = 1; i <= n; i++)  // 第一个点:矩形的左下角
    {
        for (int j = 1; j <= n; j++)  // 第二个点:与第一个点同x轴
        {
            for (int k = 1; k <= n; k++)  // 第三个点:与第一个点同y轴
            {
                // 检查是否能构成与坐标轴平行的矩形
                // 条件1: 点i和点k有相同的x坐标(垂直线段)
                // 条件2: 点j和点i有相同的y坐标(水平线段)
                if (x[i] == x[k] && y[j] == y[i])
                {
                    // 计算矩形面积 = 宽度 * 高度
                    // 宽度 = |x[i] - x[j]| (点i和点j的x坐标差)
                    // 高度 = |y[i] - y[k]| (点i和点k的y坐标差)
                    int area = abs(y[i] - y[k]) * abs(x[i] - x[j]);
                    ans = max(ans, area);  // 更新最大面积
                }
            }
        }
    }
    
    cout << ans << endl;  // 输出最大矩形面积
    return 0;
}

【运行结果】

4
0 0
0 1
1 0
1 2
2

疯狂的科学家

【题目来源】

学而思编程:疯狂的科学家

【题目描述】

Farmer John 的远房亲戚 Ben 是一个疯狂的科学家。通常这会在家庭聚会时造成不小的摩擦,但这偶尔也会带来些好处,尤其是当 Farmer John 发现他正面对一些有关他的奶牛们的独特而不寻常的问题时。

Farmer John 当前正面对一个有关她的奶牛们的独特而不寻常的问题。他最近订购了 \(N\) 头奶牛(\(1≤N≤1000\)),包含两种不同品种:荷斯坦牛和更赛牛。他在订单中用一个长为 \(N\) 的字符串来指定奶牛,其中的字符为 H(表示荷斯坦牛)或 G(表示更赛牛)。不幸的是,当这些奶牛到达他的农场,他给她们排队时,她们的品种组成的字符串与原先的不同。

我们将这两个字符串称为 \(A\)\(B\),其中 \(A\) 是 Farmer John 原先想要的品种字符组成的字符串,\(B\) 是他的奶牛们到达时组成的字符串。Farmer John 并没有简单地检查重新排列 \(B\) 中的奶牛是否能得到 \(A\),而是请他的远房亲戚 Ben 利用他的科学才华来解决这一问题。

经过数月的研究,Ben 发明了一台不同寻常的机器:奶牛品种转换机,能够选择任意奶牛组成的子串并反转她们的品种:在这个子串中的所有 H 变为 G,所有 G 变为 H。Farmer John 想要求出将他当前的序列 \(B\) 变为他本来订购时想要的 \(A\) 需要使用这台机器的最小次数。然而,Ben 的疯狂的科学家技能并不会处理开发奇异机器以外的事,所以你需要帮助 Farmer John 解决这个计算难题。

【输入】

输入的第一行包含 \(N\),以下两行包含字符串 \(A\)\(B\)。每个字符串均包含 \(N\) 个字符,字符均为 H 和 G 之一。

【输出】

输出将 \(B\) 变为 \(A\) 需要使用机器的最小次数。

【输入样例】

7
GHHHGHH
HHGGGHH

【输出样例】

2

【代码详解】

#include <bits/stdc++.h>
using namespace std;

int main()
{
    int n;  // 字符串长度
    string a, b;  // 两个字符串
    cin >> n >> a >> b;  // 读入长度和两个字符串
    
    int cnt = 0, flag = 1;  // cnt: 不同段数量,flag: 标记是否在新的一段中
    
    for (int i = 0; i < n; i++)  // 遍历每个位置
    {
        // 如果当前位置字符不同,且flag为1(表示新的一段开始)
        if (a[i] != b[i] && flag)
        {
            cnt++;  // 不同段数量加1
            flag = 0;  // 标记进入当前不同段
        }
        
        // 如果当前位置字符相同
        if (a[i] == b[i])
        {
            flag = 1;  // 标记可以开始新的不同段
        }
    }  
    
    cout << cnt << endl;  // 输出不同段的数量
    return 0;
}

【运行结果】

7
GHHHGHH
HHGGGHH
2

更奇怪的照片

【题目来源】

学而思编程:更奇怪的照片

【题目描述】

Farmer John 正再一次尝试给他的 \(N\) 头奶牛拍照(\(2≤N≤1000\))。

每头奶牛有一个范围在 \(1…100\) 之内的整数的「品种编号」。Farmer John 对他的照片有一个十分古怪的构思:他希望将所有的奶牛分为不相交的若干组(换句话说,将每头奶牛分到恰好一组中)并将这些组排成一行,使得第一组的奶牛的品种编号之和为偶数,第二组的编号之和为奇数,以此类推,奇偶交替。

Farmer John 可以分成的最大组数是多少?

【输入】

输入的第一行包含 \(N\)。下一行包含 \(N\) 个空格分隔的整数,为 \(N\) 头奶牛的品种编号。

【输出】

输出 Farmer John 的照片中的最大组数。可以证明,至少存在一种符合要求的分组方案。

【输入样例】

7
1 3 5 7 9 11 13

【输出样例】

3

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int n, odd, even;  // n: 数字个数,odd: 奇数个数,even: 偶数个数

int main()
{
    cin >> n;  // 读入数字个数
    
    for (int i = 1; i <= n; i++)  // 遍历每个数字
    {
        int t;
        cin >> t;  // 读入当前数字
        
        if (t % 2 == 0)  // 如果是偶数
        {
            even++;  // 偶数计数加1
        }
        else  // 如果是奇数
        {
            odd++;  // 奇数计数加1
        }
    }
    
    // 调整奇偶数量,使它们可以交替排列
    while (odd > even)  // 当奇数多于偶数时
    {
        odd -= 2;  // 将两个奇数合并成一个偶数
        even++;    // 合并后得到一个偶数
    }
    
    if (even > odd)  // 如果偶数多于奇数
    {
        even = odd + 1;  // 最多只能多一个偶数
    }
    
    // 输出最大交替序列长度
    cout << even + odd << endl;  // 总长度是奇数和偶数个数之和
    return 0;
}

【运行结果】

7
1 3 5 7 9 11 13
3

普及进阶组

重新涂色

【题目来源】

学而思编程:重新涂色

【题目描述】

有一个 \(H\)\(W\) 列的方格棋盘, 从上数第 \(i\) 行,从左数第 \(j\) 列的格子记为 \((i,j)\). 小猴从 \((1,1)\) 出发, 每次可以走到上下左右的相邻格子, 目标是走到 \((H,W)\). 方格被涂成了黑色和白色, 小猴只能进入白色的格子, 不能进入黑色格子.

在游戏开始前, 小猴可以将任意多个白色格子涂黑, 但是不能涂黑起点 \((1,1)\) 和终点 \((H,W)\). 涂色必须在游戏开始前完成, 开始游戏后就不能涂黑格子了.

到达终点后, 小猴能得到的分数等于游戏开始前涂黑的格子的数量, 给出初始的棋盘状态, 求出小猴能得到的最高分数. 如果无法到达终点, 输出 \(-1\).

【输入】

第一行, \(2\) 个正整数 \(H,W\), 表示棋盘行数和列数

接下来 \(H\) 行, 每行 \(W\) 个字符, 给出棋盘初始状态, '#'表示黑格, '.'表示白格

【输出】

输出小猴能得到的最高分数, 若无法到达终点, 输出 \(-1\).

【输入样例】

3 3
..#
#..
...

【输出样例】

2

【解题思路】

image

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 55;

int n, m, cnt;
char g[N][N];       // 地图
int dist[N][N];     // 存储从起点到每个位置的最短距离
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};

struct Node
{
    int x, y;
};
queue<Node> q;

// 广度优先搜索,计算从起点(1,1)到所有可到达位置的最短距离
void bfs()
{
    q.push((Node){1, 1});
    memset(dist, -1, sizeof(dist));
    dist[1][1] = 0;
    while (!q.empty())
    {
        int x = q.front().x, y = q.front().y;
        q.pop();
        for (int i = 0; i < 4; i++)
        {
            int nx = x + dx[i], ny = y + dy[i];
            // 检查边界
            if (nx < 1 || nx > n || ny < 1 || ny > m)
            {
                continue;
            }
            // 检查是否是障碍物
            if (g[nx][ny] == '#')
            {
                continue;
            }
            // 检查是否已访问
            if (dist[nx][ny] != -1)
            {
                continue;
            }
            dist[nx][ny] = dist[x][y] + 1;
            q.push((Node){nx, ny});
        }
    }
}

int main()
{
    cin >> n >> m;
    for (int i = 1; i <= n; i++)
    {
        for (int j = 1; j <= m; j++)
        {
            cin >> g[i][j];
            // 统计空地数量
            if (g[i][j] == '.')
            {
                cnt++;
            }
        }
    }

    bfs();
    // 如果无法到达终点
    if (dist[n][m] == -1)
    {
        cout << -1 << endl;
    }
    else
    {
        // 输出结果:总空地数 - 最短路径经过的格子数
        // dist[n][m]是从起点到终点的步数,+1是因为包括起点
        cout << cnt - (dist[n][m] + 1) << endl;
    }
    return 0;
}

【运行结果】

3 3
..#
#..
...
2

六面世界3

【题目来源】

六面世界3

【题目描述】

如下所示,有一个无限扩展的六边形网格。最初,所有格子都是白色的。

image

一个六边形格子用两个整数 \(i,j\) 表示为 \((i,j)\)
格子 \((i,j)\) 与以下 \(6\) 个格子相邻:

\((i−1,j−1)\)

\((i−1,j)\)

\((i,j−1)\)

\((i,j+1)\)

\((i+1,j)\)

\((i+1,j+1)\)

现在有 \(N\) 个格子 \((X_1,Y_1),(X_2,Y_2),…,(X_N,Y_N)\) 被涂成了黑色。

如果两个黑色格子之间可以通过若干个相邻的黑色格子移动到达,则认为这两个黑色格子属于同一个连通分量。请你求出黑色格子构成的连通分量的个数。

【输入】

第一行,一个正整数 \(N\)

接下来 \(N\) 行,每行两个整数 \((X_i,Y_i)\),表示黑色格子的坐标。

【输出】

输出黑色格子构成的连通分量的个数。

【输入样例】

6
-1 -1
0 1
0 2
1 0
1 2
2 0

【输出样例】

3

【代码详解】

#include <bits/stdc++.h>
using namespace std;
const int N = 2005;

int a[N][N];  // 标记哪些位置有点
int n, cnt;
bool vis[N][N];  // 标记是否访问过
// 六个方向的偏移量,对应六边形的六个方向
int dx[] = {1, -1, 0, 0, 1, -1};
int dy[] = {0, 0, 1, -1, 1, -1};

// 深度优先搜索
void dfs(int x, int y)
{
    vis[x][y] = 1;
    for (int i = 0; i < 6; i++)
    {
        int nx = x + dx[i];
        int ny = y + dy[i];
        // 检查边界
        if (nx < 1 || nx > 2000 || ny < 1 || ny > 2000)
        {
            continue;
        }
        // 检查该位置是否有雪球
        if (a[nx][ny] == 0)
        {
            continue;
        }
        // 检查是否已访问
        if (vis[nx][ny] == 1)
        {
            continue;
        }
        vis[nx][ny] = 1;
        dfs(nx, ny);
    }
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; i++)
    {
        int x, y;
        cin >> x >> y;
        // 坐标偏移,避免负坐标
        x += 1000, y += 1000;
        a[x][y] = 1;  // 标记雪球位置
    }
    
    // 遍历整个网格
    for (int i = 0; i <= 2000; i++)
    {
        for (int j = 0; j <= 2000; j++)
        {
            // 如果这个位置有雪球且未访问过
            if (a[i][j] == 1 && vis[i][j] == 0)
            {
                dfs(i, j);
                cnt++;  // 发现一个新的连通块
            }
        }
    }

    cout << cnt << endl;
    return 0;
}

【运行结果】

6
-1 -1
0 1
0 2
1 0
1 2
2 0
3
posted @ 2026-03-20 14:27  团爸讲算法  阅读(1)  评论(0)    收藏  举报