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

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

语言基础组

三角形类型

【题目来源】

学而思编程:三角形类型

【题目描述】

读取表示三角形三条边的 \(3\) 个正整数 \(A\)\(B\)\(C\) 并按降序排列,使 \(A\) 边是三边中最大的一边。

接下来,根据以下情况,确定它们可以组成的三角形类型:

如果 \(A\ge B+C\),则说明三条边不能构成三角形,请输出:NAO FORMA TRIANGULO

否则,说明三条边可以构成三角形,然后按如下情况输出:

如果 \(A^2=B^2+C^2\),请输出:TRIANGULO RETANGULO

如果 \(A^2\gt B^2+C^2\),请输出:TRIANGULO OBTUSANGULO

如果 \(A^2\lt B^2+C^2\),请输出:TRIANGULO ACUTANGULO

如果三个边长度都相同,请输出:TRIANGULO EQUILATERO

如果只有两个边长度相同而第三个边长度不同,请输出:TRIANGULO ISOSCELES

【输入】

共一行,包含三个正整数 \(A,B,C\)

【输出】

输出 \(A,B,C\) 组成的三角形的类型。

注意,上述条件可能满足不止一条,这种情况下将所有类型名称,按题目介绍顺序输出,每行输出一条。

【输入样例】

7 5 7

【输出样例】

TRIANGULO ACUTANGULO
TRIANGULO ISOSCELES

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int a, b, c;

int main()
{
    cin >> a >> b >> c;
    // 将最大数交换到a的位置
    if (a < b)
    {
        int t = a;
        a = b;
        b = t;
    }
    if (a < c)
    {
        int t = a;
        a = c;
        c = t;
    }
    
    // 检查是否能构成三角形
    if (a >= b + c)
    {
        cout << "NAO FORMA TRIANGULO" << endl;
    }
    else
    {
        // 判断三角形类型
        if (a * a == b * b + c * c)
        {
            cout << "TRIANGULO RETANGULO" << endl;  // 直角三角形
        }
        if (a * a > b * b + c * c)
        {
            cout << "TRIANGULO OBTUSANGULO" << endl;  // 钝角三角形
        }
        if (a * a < b * b + c * c)
        {
            cout << "TRIANGULO ACUTANGULO" << endl;  // 锐角三角形
        }
        if (a == b && b == c)
        {
            cout << "TRIANGULO EQUILATERO" << endl;  // 等边三角形
        }
        // 判断等腰三角形
        if (a == b && c != a && c != b || a == c && b != a && b != c || b == c && a != b && a != c)
        {
            cout << "TRIANGULO ISOSCELES" << endl;  // 等腰三角形
        }
    }
    return 0;
}

【运行结果】

7 5 7
TRIANGULO ACUTANGULO
TRIANGULO ISOSCELES

划拳

【题目来源】

学而思编程:划拳

【题目描述】

小王和小明在吃饭的时候玩起了划拳游戏。

游戏规则是,每一轮两个人同时说出一个数(只能是 \(5,10,15,20\) 中的一个),若两人说出的数一样,则两人均不计分,否则说出数字更大的人获得两人说出的数差值这么多的分数。

但有一个例外,如果一个人说的 \(20\),但另一个说的是 \(5\)\(10\),则说 \(20\) 的这个人不得分,另一个人得 \(10\) 分。

游戏共进行 \(k\) 轮,求最后两人各自得分。

【输入】

第一行一个整数 \(k\),表示游戏进行的轮数。

接下来 \(k\) 行,每行两个整数分别表示这一轮小王和小明说的数。

【输入】

第一行一个整数 k,表示游戏进行的轮数。

接下来 k 行,每行两个整数分别表示这一轮小王和小明说的数。

【输出】

一行输出两个整数以空格分开。

分别为小王和小明的得分。

【输入样例】

2
10 15
20 10

【输出样例】

0 15

【代码详解】

#include <bits/stdc++.h>
using namespace std;
int a, b, k;

int main()
{
    cin >> k;
    for (int i = 1; i <= k; i++)
    {
        int x, y;
        cin >> x >> y;
        // 特殊规则:当一方为20,另一方为5或10时
        if (x == 20 && (y == 5 || y == 10))
        {
            b += 10;  // 玩家b获得10分
        }
        else if (y == 20 && (x == 5 || x == 10))
        {
            a += 10;  // 玩家a获得10分
        }
        else
        {
            // 一般规则:分数高的一方获得差值分数
            if (x > y)
            {
                a += x - y;  // 玩家a获得差值
            }
            else
            {
                b += y - x;  // 玩家b获得差值
            }
        }
    }
    cout << a << " " << b << endl;
    return 0;
}

【运行结果】

2
10 15
20 10
0 15

排位

【题目来源】

学而思编程:排位

【题目描述】

\(n\) 个人排成了一队,小X就在其中。

他不知道自己的确切排位,但是他能确定的是,排在他前面的人不少于 \(a\) 个,排在他后面的人不超过 \(b\) 个。

请问,对于他的具体排位,一共有多少种可能性?

【输入】

第一行包含整数 \(T\),表示共有 \(T\) 组数据。

每组数据占一行,包含三个整数 \(n,a,b\)

【输出】

每组数据输出一行结果,一个整数,表示小X具体排位的可能数量。

【输入样例】

2
3 1 1
5 2 3

【输出样例】

2
3

【代码详解】

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

int main()
{
    cin >> t;
    for (int i = 1; i <= t; i++)
    {
        int n, a, b;
        cin >> n >> a >> b;
        // 分三种情况计算
        if (a + b == n)
        {
            cout << b << endl;  // 如果刚好坐满,则b的个数就是b
        }
        if (a + b < n)
        {
            cout << b + 1 << endl;  // 如果还有空位,b可以多坐一个人
        }
        if (a + b > n)
        {
            cout << n - a << endl;  // 如果座位不够,剩余的座位全给b
        }
    }
    return 0;
}

【运行结果】

2
3 1 1
2
5 2 3
3

普及奠基组

唯一最小数

【题目来源】

学而思编程:唯一最小数

【题目描述】

给定一个长度为 \(n\) 的整数数组 \(a_1,a_2,\dots ,a_n\)

请你找到数组中只出现过一次的数当中最小的那个数。

输出找到的数的索引编号

\(a_1\) 的索引编号为 \(1\)\(a_2\) 的索引编号为 \(2\),…,\(a_n\) 的索引编号为 \(n\)

【输入】

第一行包含整数 \(T\),表示共有 \(T\) 组测试数据。

每组数据第一行包含整数 \(n\)

第二行包含 \(n\) 个整数 \(a_1,a_2,\dots ,a_n\)

【输出】

每组数据输出一行结果,即满足条件的数的索引编号,如果不存在满足条件的数,则输出 \(−1\)

【输入样例】

2
2
1 1
3
2 1 3

【输出样例】

-1
2

【代码详解】

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

int a[N], cnt[N];

int main()
{
    int T;
    cin >> T;
    while (T--)
    {
        int n;
        cin >> n;
        memset(cnt, 0, sizeof(cnt));  // 重置计数数组
        for (int i = 1; i <= n; i++)
        {
            cin >> a[i];
            cnt[a[i]]++;  // 统计每个数字出现的次数
        }
        int ans = -1;
        for (int i = 1; i <= n; i++)
        {
            // 寻找只出现一次的数字
            if (cnt[a[i]] == 1)
            {
                // 更新答案为最小值的索引
                if (ans == -1 || a[ans] > a[i])
                {
                    ans = i;
                }
            }
        }
        cout << ans << endl;  // 输出索引,如果不存在则输出-1
    }
    return 0;
}

【运行结果】

2
2
1 1
-1
3
2 1 3
2

解密

【题目来源】

学而思编程:解密

【题目描述】

上一次,小猴的加密方式很快就被破解掉了,后来他学习了一个很经典的加密方式——“凯撒密码”,可是他觉得这个也很容易就会被别人破解,所以他决定创造一种“猴氏撒密码”。

和“凯撒密码”一样,“猴氏撒密码撒密码”也是利用字母向后偏移来实现的,但是他觉得偏移值如果固定的话也很容易被人破解,所以在加密后还会把这个字母再加上偏移值个数,例如 "\(a\)" 在偏移值为 \(3\) 时,会被加密为 "\(dddd\)"。如果保证明文中相邻字母加密后的字母不会相同,现在给出你一个加密后的结果,你能把明文找出来

【输入】

第一行一个仅由小写字母组成的的字符串 \(s\),表示加密后的结果。

【输出】

一个字符串表示加密前的明文。

【输入样例】

aaadddd

【输出样例】

ya

【代码详解】

#include <bits/stdc++.h>
using namespace std;
char s[1000005];

int main()
{
    cin >> s + 1;  // 从下标1开始读取字符串
    int n = strlen(s + 1);
    int k = 0;  // 记录当前连续相同字符的数量
    for (int i = 1; i <= n; i++)
    {
        k++;
        // 如果当前字符和下一个字符不同,或者到达字符串末尾
        if (s[i] != s[i + 1])
        {
            // 还原原始字符:从加密字符减去连续的次数(取模26)
            char ch = (s[i] - 'a' - (k - 1) % 26 + 26) % 26 + 'a';
            cout << ch;
            k = 0;  // 重置计数器
        }
    }
    return 0;
}

【运行结果】

aaadddd
ya

懒惰的牛

【题目来源】

学而思编程:赛事平台

【题目描述】

这是一个炎热的夏日。懒洋洋的奶牛贝茜想将自己放置在田野中的某个位置,以便可以在短距离内尽可能多地吃到美味的草。

贝茜所在的田野中共有 \(N\) 片草地,我们可以将田野视作一个一维数轴。第 \(i\) 片草地中包含 \(g_i\) 单位的青草,位置坐标为 \(x_i\)。不同草地的位置不同。

贝茜想选取田野中的某个点作为她的初始位置(可能是某片草地所在的点)。只有一片草地与她的初始位置的距离不超过 \(K\) 时,贝茜才能吃到那片草地上的草。

如果贝茜选择最佳初始位置,请确定她可以吃到的青草最大数量。

【输入】

第一行包含两个整数 \(N\)\(K\)

接下来 \(N\) 行,每行描述一片草地,包含两个整数 \(g_i\)\(x_i\)

【输出】

输出如果贝茜选择最佳初始位置,则她可以吃到的青草最大数量。

【输入样例】

4 3
4 7
10 15
2 2
5 1

【输出样例】

11

【代码详解】

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

int a[N], s[N];  // a数组记录每个位置的冰淇淋数量,s数组是前缀和

int main()
{
    int n, k;
    cin >> n >> k;
    int len = 0;  // 记录最大的位置坐标
    for (int i = 1; i <= n; i++)
    {
        int g, x;
        cin >> g >> x;
        a[x + 1] = g;  // 位置从1开始,所以x+1
        len = max(len, x + 1);  // 更新最大位置
    }
    // 计算前缀和
    for (int i = 1; i <= len; i++)
    {
        s[i] = s[i - 1] + a[i];
    }
    int ans = 0;
    // 遍历每个位置作为中心
    for (int i = 1; i <= len; i++)
    {
        // 计算覆盖范围
        int l = max(1, i - k), r = min(i + k, len);
        // 使用前缀和快速计算区间和
        int sum = s[r] - s[l - 1];
        ans = max(ans, sum);
    }
    cout << ans << endl;
    return 0;
}

【运行结果】

4 3
4 7
10 15
2 2
5 1
11

普及进阶组

posted @ 2026-03-20 15:07  团爸讲算法  阅读(1)  评论(0)    收藏  举报