学而思编程每周练习赛 | 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
浙公网安备 33010602011771号