学而思编程每周练习赛 | 2025年春第2周
附上学而思公众号链接:学而思编程每周练习赛-第02周-习题视频讲解与试题分析
语言基础组
最大面积
【题目来源】
学而思编程:最大面积
【题目描述】
有 \(n\) 个圆,每个圆的半径依次为 \(r_1,r_2,…,r_n\),请计算求出这 \(n\) 个圆的最大面积,结果四舍五入保留 \(2\) 位小数。
【输入】
第一行,包含一个整数 \(n\)。
第二行,包含 \(n\) 个正整数 \(r_1,r_2,…,r_n\),依次表示每个圆的半径。
【输出】
一行,一个实数,结果四舍五入保留 \(2\) 位小数。
【输入样例】
3
2 1 3
【输出样例】
28.27
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 100; // 定义常量 N,表示数组的最大长度
int n; // n 表示输入的数字个数
int a[N]; // 数组 a 用于存储输入的数字(未使用)
double ans = -1e9; // ans 用于记录最大面积,初始化为一个很小的值
int main()
{
cin >> n; // 输入数字的个数 n
for (int i = 1; i <= n; i++) // 遍历每个数字
{
int x;
cin >> x; // 输入当前数字 x
// 计算当前数字对应的圆的面积,并更新最大值
ans = max(ans, 1.0 * x * x * 3.1415926);
}
printf("%.2lf\n", ans); // 输出最大面积,保留两位小数
return 0;
}
【运行结果】
3
2 1 3
28.27
双重质数
【题目来源】
学而思编程:双重质数
【题目描述】
正整数可分为:单位(即 \(1\))、质数与合数三类。每个质数有且仅有两个因数(\(1\) 和它本身)。注意 \(1\) 既不是质数,也不是合数。
有一些数,它自身是质数,在十进制表示下,如果去掉它的个位数,仍然是一个质数。我们称这种质数为双质数。
例如,\(23\)、\(593\)、\(1931\) 都是双质数。而 \(17\) 不是,因为 \(1\) 不算质数。
给定两个正整数 \(a\) 和 \(b\)。请在 \(a\) 到 \(b\) 的范围内(包含 \(a\) 和 \(b\)),寻找并输出所有的双质数。
【输入】
两个正整数表示 \(a\) 和 \(b\)。
【输出】
若干行,每行输出一个双质数,如果一个都没有,则输出 None。
【输入样例】
20 50
【输出样例】
23
29
31
37
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int a, b; // 定义变量 a 和 b,表示范围的起点和终点
// 判断一个数是否为质数的函数
bool isPrime(int x)
{
if (x < 2) return false; // 小于 2 的数不是质数
for (int i = 2; i <= x / i; i++) // 遍历 2 到 sqrt(x)
if (x % i == 0) return false; // 如果 x 能被 i 整除,则 x 不是质数
return true; // 否则 x 是质数
}
int main()
{
cin >> a >> b; // 输入范围的起点 a 和终点 b
// 遍历范围 [a, b] 中的每个数
for (int i = a; i <= b; i++)
{
// 如果当前数 i 是质数,且去掉个位数后的数也是质数
if (isPrime(i) && isPrime(i / 10))
cout << i << endl; // 输出当前数 i
}
return 0;
}
【运行结果】
20 50
23
29
31
37
xyz
【题目来源】
学而思编程:xyz
【题目描述】
有三个正整数 \(x,y,z\),我们不知道每个数的具体值,但我们知道 \(x≤y≤z\)。
现在,以随机顺序给出 \(x+y,x+z,y+z,x+y+z\) 的值,请你求出 \(x,y,z\) 的值。
题目保证一定有解。
【输入】
共一行,包含四个整数 \(x_1,x_2,x_3,x_4\),表示以随机顺序给出的 \(x+y,x+z,y+z,x+y+z\) 的值。
【输出】
共一行,三个空格隔开的整数 \(x,y,z\)。
【输入样例】
3 6 5 4
【输出样例】
1 2 3
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 5; // 定义常量 N,表示数组的最大长度
int a[N]; // 定义数组 a,用于存储输入的 4 个数
int main()
{
// 输入 4 个数
for (int i = 1; i <= 4; i++)
cin >> a[i];
// 对数组 a 的第 1 到第 4 个元素进行升序排序
sort(a + 1, a + 5);
// 输出结果:a[4] - a[3], a[4] - a[2], a[4] - a[1]
cout << a[4] - a[3] << " " << a[4] - a[2] << " " << a[4] - a[1] << endl;
return 0;
}
【运行结果】
3 6 5 4
1 2 3
普及奠基组
字符串加密
【题目来源】
学而思编程:字符串加密
【题目描述】
在密码学中,我们称需要加密的信息为明文,用 \(M\) 表示;称加密后的信息为密文,用 \(C\) 表示;而密钥是一种参数,是将明文转换为密文或将密文转换为明文的算法中输入的数据,记为 \(k\)。
上一次,小猴的加密方式很快就被破解掉了,后来他研究了一种简单的加密算法,用来处理只包含大小写英文字符的字符串:
- 首先,将字符串中的字母进行大小转换,即将大写字母改成对应小写字母,将小写字母改成对应大写字母;
- 然后,将字符串中第一个字母与最后一个字母对调,第二个字母与倒数第二个字母对调,其他字母以此类推。显然,对调字母的次数等于字符串长度的一半(向下取整)。
现在,给定一个已经被小猴加密过的字符串 \(C\),请你解密出原来的字符串 \(M\)。
【输入】
一行,包含一个字符串 \(C\)。
【输出】
一行,包含一个字符串,表示经过解密的内容。
【输入样例】
EDOcUOhOAIx
【输出样例】
XiaoHouCode
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
string s; // s 表示输入的字符串
int main()
{
// 输入字符串
cin >> s;
// 遍历字符串的每个字符
for (int i = 0; i < s.length(); i++)
{
// 如果字符是小写字母,转换为大写字母
if (s[i] >= 'a' && s[i] <= 'z')
s[i] = s[i] - 32;
// 如果字符是大写字母,转换为小写字母
else if (s[i] >= 'A' && s[i] <= 'Z')
s[i] = s[i] + 32;
}
// 反转字符串
reverse(s.begin(), s.end());
// 输出处理后的字符串
cout << s << endl;
return 0;
}
【运行结果】
EDOcUOhOAIx
XiaoHouCode
美丽的数
【题目来源】
学而思编程:美丽的数
【题目描述】
如果一个正整数除了 \(1\) 和它本身之外,有且只有一个约数,则称此正整数是“美丽的”。
现在有 \(q\) 次询问,每次询问给定一个正整数 \(x_i\),请你判断 \(x_i\) 是否为一个“美丽的数”,如果 \(x_i\) 是美丽的数,则输出 Yes,否则输出 No。
【输入】
第一行,包含一个正整数 \(q\)。
接下来 \(q\) 行,每行包含一个正整数 \(x_i\),第 \(i\) 行的正整数为 \(x_i\)。
【输出】
共 \(q\) 行,其中第 \(i\) 行输出对 \(x_i\) 的判断结果,如果 \(x_i\) 是美丽的数,则输出 Yes,否则输出 No。
【输入样例】
3
4
5
6
【输出样例】
Yes
No
No
【解题思路】

【代码详解】
#include <bits/stdc++.h>
#include <cmath>
using namespace std;
// 判断一个数是否是质数
bool isPrime(long long n)
{
if (n < 2) return false; // 小于 2 的数不是质数
for (int i = 2; i * i <= n; i++) // 遍历 2 到 sqrt(n)
{
if (n % i == 0) return false; // 如果 n 能被 i 整除,则 n 不是质数
}
return true; // 否则 n 是质数
}
// 判断一个数是否是平方质数
bool check(long long n)
{
long long t = sqrt(n); // 计算 n 的平方根
if (t * t != n) return false; // 如果 t * t 不等于 n,则 n 不是完全平方数
return isPrime(t); // 判断平方根 t 是否是质数
}
int main()
{
int n; // n 表示测试用例的数量
cin >> n;
// 处理每个测试用例
while (n--)
{
long long m; // m 表示需要判断的数
cin >> m;
// 判断 m 是否是平方质数,并输出结果
if (check(m)) cout << "Yes" << endl;
else cout << "No" << endl;
}
return 0;
}
【运行结果】
3
4
Yes
5
No
6
No
全都为1*
【题目来源】
学而思编程:全都为1
【题目描述】
小猴和朋友正在玩一个游戏,初始时,在一个 \(n×n\) 的棋盘上放置着 \(n×n\) 个棋子,棋子只有黑色和白色两种,其中棋盘左上角的坐标为 \((1,1)\),右下角的坐标为 \((n,n)\)。
小猴可以进行任意次操作,每次操作小猴会在棋盘内选择一个位置 \((x,y)\),然后将该位置与棋盘右下角 \((n,n)\) 形成的矩形范围内所有棋子进行更换为颜色相反的棋子,即白色棋子换成黑色棋子,黑色棋子换成白色棋子。
我们使用数字 \(0\) 代表白色棋子,数字 \(1\) 代表黑色棋子,则有如下例子:

如上图,选择坐标为 \((3,2)\) 的位置,这样就将整个棋盘的棋子全部变成黑色。
请问小猴最少需要操作多少次,才能使得整个 \(n×n\) 的棋盘中的所有棋子都为黑色。
【输入】
第一行,包含一个整数 \(n\);
接下来 \(n\) 行,每行 \(n\) 个整数 \(a_{i,1},a_{i,2},…,a_{i,n}\),其中 \(a_{i,j}\) 表示棋盘位置坐标为 \((i,j)\) 的棋子颜色,\(0\) 表示白色,\(1\) 表示黑色。
【输出】
一行,包含一个整数,表示小猴最少需要操作的步数。
【输入样例】
4
1 1 1 1
1 1 1 1
1 0 0 0
1 0 0 0
【输出样例】
1
【解题思路】

【代码详解】
#include <bits/stdc++.h>
using namespace std;
int n; // n 表示矩阵的大小
int a[2005][2005]; // a[i][j] 表示矩阵的第 i 行第 j 列的元素
int f[2005][2005]; // f[i][j] 表示从 (1,1) 到 (i,j) 的子矩阵中满足条件的元素数量
int main()
{
// 输入矩阵的大小
cin >> n;
// 输入矩阵的元素
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
cin >> a[i][j];
}
}
// 动态规划求解
for (int i = 1; i <= n; i++)
{
for (int j = 1; j <= n; j++)
{
// 计算 f[i][j] 的初始值
f[i][j] = f[i - 1][j] + f[i][j - 1] - f[i - 1][j - 1];
// 根据 f[i-1][j] + f[i][j-1] - f[i-1][j-1] 的奇偶性更新 f[i][j]
if (f[i][j] % 2 == 1) // 如果是奇数
{
if (a[i][j] == 1) f[i][j]++; // 如果 a[i][j] 是 1,则 f[i][j] 加 1
}
else // 如果是偶数
{
if (a[i][j] == 0) f[i][j]++; // 如果 a[i][j] 是 0,则 f[i][j] 加 1
}
}
}
// 输出结果
cout << f[n][n] << endl;
return 0;
}
【运行结果】
4
1 1 1 1
1 1 1 1
1 0 0 0
1 0 0 0
1
普及进阶组
拿香蕉(强)
【题目来源】
学而思编程:拿香蕉(强)
【题目描述】
小猴的桌子上放着 \(n\) 个香蕉从左到右排成一列,编号为从 \(1\) 到 \(n\)。
小美是小猴的好朋友,每天她都会从中拿走一些香蕉。
每天在拿的时候,小美都是从左侧第 \(1\) 个香蕉开始,把第 \(1,3,5,…,2k−1(2k−1≤n)\) 个香蕉拿走。随后小美会将剩下的香蕉按原先的顺序重新排成一列。
小美想知道,编号为 \(n\) 的香蕉是在第几天被拿走的?
【输入】
输入的第一行包含一个正整数 \(n\),表示香蕉的总数。
【输出】
输出一行包含一个正整数,表示小美拿走编号为 \(n\) 的香蕉是在第几天。
【输入样例】
6
【输出样例】
2
【代码详解】
#include <bits/stdc++.h>
using namespace std;
const int N = 5005; // 定义常量 N,表示数组的最大长度
int A[N], b, r; // A 数组用于存储大整数,b 是除数,r 是余数
// 高精度除法函数:A / b = C ... r
void div(int A[], int b, int C[], int& r) {
r = 0; // 初始化余数为 0
for (int i = A[0]; i > 0; --i) { // 从高位到低位遍历 A
r = r * 10 + A[i]; // 计算当前位的被除数
C[i] = r / b; // 计算当前位的商
r %= b; // 计算当前位的余数
}
// 确定商的位数
C[0] = A[0]; // 商的位数初始化为 A 的位数
while (C[0] > 1 && C[C[0]] == 0) --C[0]; // 去掉商的前导 0
}
int main()
{
string a;
cin >> a; // 输入大整数的字符串表示
A[0] = a.length(); // A[0] 存储大整数的位数
for (int i = 0; i < A[0]; i++)
A[A[0] - i] = a[i] - '0'; // 将字符串转换为数组,A[1] 是最低位,A[A[0]] 是最高位
int ans = 1; // 初始化结果为 1
while (A[1] % 2 == 0) // 如果 A 的最低位是偶数
{
div(A, 2, A, r); // 将 A 除以 2,结果存回 A
ans++; // 结果加 1
}
cout << ans << endl; // 输出结果
return 0;
}
【运行结果】
6
2
对角线数独
【题目来源】
学而思编程:对角线数独
【题目描述】
对角线数独是从数独衍生出的一个变种。在 \(9×9\) 的大九宫格中填入数字 \(1∼9\),使他们满足如下规则:每行、每列和每个小九宫格内不能出现一样的数字,在每条大对角线中也不能出现一样的数字。
以下是一个例子:

【输入】
输入共 \(9\) 行,每行 \(9\) 个用空格隔开的一位整数,这些数展示了需要填写完成的数独表格。
保证每个数都是 \(0∼9\) 范围内的正整数,其中 \(0\) 表示需要填写。
注意一个正确的数独题的解是存在且唯一的,本题的数据也保证这一点。
【输出】
输出共 \(9\) 行,每行 \(9\) 个用空格隔开的整数,这些数展示了整个填写完成的数独表格。
每个数应都是 \(1∼9\) 范围内的正整数。
【输入样例】
6 7 0 0 0 9 0 8 0
0 0 0 0 5 0 9 0 3
0 0 0 0 0 6 0 0 0
0 0 9 0 0 0 0 5 0
0 0 0 0 0 4 0 7 9
4 0 0 0 6 0 0 0 2
0 4 0 6 9 0 5 0 0
0 0 0 0 0 0 0 0 6
0 0 0 8 7 3 0 0 0
【输出样例】
6 7 5 3 2 9 1 8 4
8 2 1 4 5 7 9 6 3
9 3 4 1 8 6 7 2 5
3 6 9 7 1 2 4 5 8
1 8 2 5 3 4 6 7 9
4 5 7 9 6 8 3 1 2
2 4 8 6 9 1 5 3 7
7 1 3 2 4 5 8 9 6
5 9 6 8 7 3 2 4 1
【代码详解】
#include <bits/stdc++.h>
using namespace std;
int a[15][15]; // 定义一个15x15的二维数组,用于存储数独的初始状态
// 检查在 (x, y) 位置填入 num 是否合法
bool isValid(int x, int y, int num) {
// 检查行
for (int i = 0; i < 9; i++) {
if (a[x][i] == num) return false; // 如果同一行存在相同的数字,返回false
}
// 检查列
for (int i = 0; i < 9; i++) {
if (a[i][y] == num) return false; // 如果同一列存在相同的数字,返回false
}
// 检查 3x3 宫
int sx = (x / 3) * 3; // 计算3x3宫的起始行
int sy = (y / 3) * 3; // 计算3x3宫的起始列
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
if (a[sx + i][sy + j] == num) return false; // 如果3x3宫内存在相同的数字,返回false
}
}
// 检查主对角线
if (x == y) {
for (int i = 0; i < 9; i++) {
if (a[i][i] == num) return false; // 如果主对角线上存在相同的数字,返回false
}
}
// 检查副对角线
if (x + y == 8) {
for (int i = 0; i < 9; i++) {
if (a[i][8 - i] == num) return false; // 如果副对角线上存在相同的数字,返回false
}
}
return true; // 如果所有检查都通过,返回true
}
// 找到候选数字最少的空格
pair<int, int> findBestCell() {
int minCandidates = 10; // 初始化最小候选数字数量为10(大于9)
pair<int, int> bestCell = {-1, -1}; // 初始化最佳单元格为无效值
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
if (a[i][j] == 0) { // 如果当前单元格为空
int candidates = 0;
for (int num = 1; num <= 9; num++) {
if (isValid(i, j, num)) { // 检查每个数字是否可以填入当前单元格
candidates++; // 增加候选数字数量
}
}
if (candidates < minCandidates) { // 如果当前单元格的候选数字数量小于最小值
minCandidates = candidates; // 更新最小候选数字数量
bestCell = {i, j}; // 更新最佳单元格
}
}
}
}
return bestCell; // 返回最佳单元格
}
// 深度优先搜索求解数独
bool dfs() {
pair<int, int> cell = findBestCell(); // 找到候选数字最少的空格
if (cell.first == -1) return true; // 如果没有空格,说明数独已解
int x = cell.first, y = cell.second;
for (int num = 1; num <= 9; num++) {
if (isValid(x, y, num)) { // 如果当前数字可以填入当前单元格
a[x][y] = num; // 填入数字
if (dfs()) // 递归调用dfs,尝试解决剩余的数独
return true;
else
a[x][y] = 0; // 如果递归调用失败,回溯,将当前单元格清空
}
}
return false; // 如果所有数字都无法填入当前单元格,返回false
}
int main() {
// 读取数独初始状态
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cin >> a[i][j]; // 从标准输入读取数独的初始状态
}
}
// 求解数独
if (dfs()) {
// 输出解
for (int i = 0; i < 9; i++) {
for (int j = 0; j < 9; j++) {
cout << a[i][j] << " "; // 输出数独的解
}
cout << endl;
}
} else {
cout << "No Solution!" << endl; // 如果没有解,输出"No Solution!"
}
return 0;
}
【运行结果】
6 7 0 0 0 9 0 8 0
0 0 0 0 5 0 9 0 3
0 0 0 0 0 6 0 0 0
0 0 9 0 0 0 0 5 0
0 0 0 0 0 4 0 7 9
4 0 0 0 6 0 0 0 2
0 4 0 6 9 0 5 0 0
0 0 0 0 0 0 0 0 6
0 0 0 8 7 3 0 0 0
6 7 5 3 2 9 1 8 4
8 2 1 4 5 7 9 6 3
9 3 4 1 8 6 7 2 5
3 6 9 7 1 2 4 5 8
1 8 2 5 3 4 6 7 9
4 5 7 9 6 8 3 1 2
2 4 8 6 9 1 5 3 7
7 1 3 2 4 5 8 9 6
5 9 6 8 7 3 2 4 1
浙公网安备 33010602011771号