3379 字
17 分钟
GESP 2023年C++三级编程题解析

202312-1 小猫分鱼#

题目描述

海滩上有一堆鱼,NN 只小猫来分。第一只小猫把这堆鱼平均分为 NN 份,多了 i<Ni<N 个,这只小猫把多的 ii 个扔入海中,拿走了一份。第二只小猫接着把剩下的鱼平均分成 NN 份,又多了 ii 个,小猫同样把多的 ii 个扔入海中,拿走了一份。第三、第四、……,第 NN 只小猫仍是最终剩下的鱼分成 NN 份,扔掉多了的 ii 个,并拿走一份。

编写程序,输入小猫的数量 NN 以及每次扔到海里的鱼的数量 ii,输出海滩上最少的鱼数,使得每只小猫都可吃到鱼。

例如:两只小猫来分鱼 N=2N=2,每次扔掉鱼的数量为 i=1i=1,为了每只小猫都可吃到鱼,可令第二只小猫需要拿走 11 条鱼,则此时待分配的有 33 条鱼。第一只小猫待分配的鱼有 3×2+1=73\times 2+1=7 条。

输入格式

总共 22 行。第一行一个整数 NN,第二行一个整数 ii

保证 0<N<100<N<10i<Ni<N

输出格式

一行一个整数,表示满足要求的海滩上最少的鱼数。

样例输入 1

2
1

样例输出 1

7

样例输入 2

3
1

样例输出 2

25

提示

【样例解释 2】

三只小猫来分鱼 N=3N=3,每次扔掉鱼的数量为 i=1i=1,为了每只小猫都可吃到鱼,可令第三只小猫需要拿走 33 条鱼(拿走 11 条和 22 条不满足要求),则此时待分配的有 1010 条鱼。第二只小猫待分配的鱼有 10×3/2+1=1610×3/2+1 = 16 条。第一只小猫待分配的鱼有 16×3/2+1=2516×3/2+1 = 25 条。

代码解析

根据题意倒着往前推即可

#include<bits/stdc++.h>
using namespace std;
bool fish(int i, int j, int n) {
int sum = j;
for (int k = 0; k < n; k++) {
if (k != 0) {
if (sum % (n-1) != 0) {
return false;
}
sum /= (n-1);
}
sum *= n;
sum += i;
}
cout << sum;
return true;
}
int main() {
int n, i, sum;
cin >> n >> i;
for (int j = 1; ; j++) {
if (fish(i, j, n))
break;
}
return 0;
}

202312-2 单位转换#

题目描述

小杨这周的数学作业是做单位转换,喜欢编程的小杨决定编程帮他解决这些问题。

小杨只学了长度单位和重量单位,具体来说:

  • 长度单位包括千米(km)、米(m)、毫米(mm),它们之间的关系是:1km=1000m=1000000mm1\text{km} = 1000\text{m} = 1000000\text{mm}
  • 重量单位包括千克(kg)、克(g)、毫克(mg),它们之间的关系是:1kg=1000g=1000000mg1\text{kg} = 1000\text{g} = 1000000\text{mg}

小杨的作业只涉及将更大的单位转换为更小的单位,也就是说,小杨的作业只会包含如下题型:米转换为毫米,千米转换为毫米,千米转换为米,克转换为毫克,千克转换为毫克,千克转换为克。

现在,请你帮忙完成单位转换的程序。

输入格式

输入的第一行为一个整数,表示题目数量。

接下来 NN 行,每行一个字符串,表示转换单位的题目,格式为 xx 单位 1=?1 = ? 单位 22。其中,xx 为一个不超过 10001000 的非负整数, 单位 11 和 单位 22 分别为两个单位的英文缩写,保证它们都是长度单位或都是重量单位,且 单位 1单位 2 更大。

例如,如果题目需要你将 1km1\text{km} 转换为 mm\text{mm},则输入为 1 km = ? mm

保证 1N10001\le N \le 1000

输出格式

输出 NN 行,依次输出所有题目的答案,输出时,只需要将输入中的 ?? 代入答案,其余部分一字不差地输出即可。由于小杨的题目只涉及将更大的单位转换为更小的单位,并且输入的 xx 是整数,因此答案一定也是整数。

例如,如果题目需要你将 1km1\text{km} 转换为 mm\text{mm},则输入为 1 km = ? mm。则你需要输出 1 km = 1000000 mm

样例输入 1

2
1 km = ? mm
1 m = ? mm

样例输出 1

1 km = 1000000 mm
1 m = 1000 mm

样例输入 2

5
100 m = ? mm
1000 km = ? m
20 kg = ? g
200 g = ? mg
0 kg = ? mg

样例输出 2

100 m = 100000 mm
1000 km = 1000000 m
20 kg = 20000 g
200 g = 200000 mg
0 kg = 0 mg

代码解析

直接使用 cin 输入,避免之后还需要字符串分割,输入的时候可以将 ?和 = 都忽略掉

因为题目中说了只能是“大转小”,所以当第一个单位是 m 或者 g 的时候,只能是转到 mm 或者 mg,当第二个单位是 m 或者 g 的时候只能是 km 转 m 或者 kg 转 g,所以这两种可能性都是直接乘 1000,除此之外肯定是 kg 转 mg,或者 km 转 mm

void get(int n, string s1, string s2) {
int m;
if (s1 == "m" || s1 == "g")
m = 1000 * n;
else if (s2 == "m" || s2 == "g")
m = 1000 * n;
else
m = 1000000 * n;
cout << n << ' '+s1+" = " << m << ' '+s2 << endl;
}

观察函数发现代码有些繁琐,而且不管是 m 还是 g,他都是长度为 1 的字符串,所以优化后:

#include<bits/stdc++.h>
using namespace std;
void get(int n, string s1, string s2) {
int m;
if (s1.size() == 1 || s2.size() == 1)
m = 1000 * n;
else
m = 1000000 * n;
cout << n << ' '+s1+" = " << m << ' '+s2 << endl;
}
int main() {
int n;
cin >> n;
while (n--) {
int a;
string s1, s2;
cin >> a >> s1 >> s2 >> s2 >> s2;
get(a, s1, s2);
}
return 0;
}

202309-1 小杨的储蓄#

题目描述

小杨共有 NN 个储蓄罐,编号从 00N1N-1。从第 11 天开始,小杨每天都会往存钱罐里存钱。具体来说,第 ii 天他会挑选一个存钱罐 aia_i,并存入 ii 元钱。过了 DD 天后,他已经忘记每个储蓄罐里都存了多少钱了,你能帮帮他吗?

输入格式

输入 22 行,第一行两个整数 N,DN,D;第二行 DD 个整数,其中第 ii 个整数为 ai{a_i}(保证 0aiN10 \le a_i \le N-1)。

每行的各个整数之间用单个空格分隔。

保证 1N1,0001 \le N \le 1,0001D1,0001 \le D \le 1,000

输出格式

输出 NN 个用单个空格隔开的整数,其中第 ii 个整数表示编号为 i1i-1 的存钱罐中有多少钱(i=1,,Ni=1, \cdots ,N)。

样例输入 1

2 3
0 1 0

样例输出 1

4 2

样例输入 2

3 5
0 0 0 2 0

样例输出 2

11 0 4

提示

【样例解释 1】

小杨在第 11 天、第 22 天、第 33 天分别向 00 号、 11 号、 00 号存钱罐存了 11 元钱、 22 元钱、 33 元钱,因此 00 号存钱罐有 1+3=41+3=4 元钱,而 11 号存钱罐有 22 元钱。

代码解析

i 天会给 m 号存钱罐投入 i 元,所以我们只需要给 money[m] 加上 i 即可,最后输出的时候注意,下标是从 0 开始的

#include<iostream>
using namespace std;
int main() {
int N, D, money[1001] = {0};
cin >> N >> D;
for (int i = 1; i <= D; i++) {
int m;
cin >> m;
money[m] += i;
}
for (int i = 1; i <= N; i++)
cout << money[i-1] << ' ';
return 0;
}

202309-2 进制判断#

题目描述

NN 进制数指的是逢 NN 进一的计数制。例如,人们日常生活中大多使用十进制计数,而计算机底层则一般使用二进制。除此之外,八进制和十六进制在一些场合也是常用的计数制(十六进制中,一般使用字母 A 至 F 表示十至十五)。

现在有N个数,请你分别判断他们是否可能是二进制、八进制、十进制、十六进制。例如,15A6F 就只可能是十六进制,而 1011 则是四种进制皆有可能。

输入格式

输入的第一行为一个十进制表示的整数 NN。接下来 NN 行,每行一个字符串,表示需要判断的数。保证所有字符串均由数字和大写字母组成,可能以 00 开头。保证不会出现空行。

保证 1N10001 \le N \le 1000,保证所有字符串长度不超过 1010

输出格式

输出 NN 行,每行 44 个数,用空格隔开,分别表示给定的字符串是否可能表示一个二进制数、八进制数、十进制数、十六进制数。使用 11 表示可能,使用 00 表示不可能。

例如,对于只可能是十六进制数的 15A6F,就需要输出 0 0 0 1;而对于四者皆有可能的 1011,则需要输出 1 1 1 1

样例输入 1

2
15A6F
1011

样例输出 1

0 0 0 1
1 1 1 1

样例输入 2

4
1234567
12345678
FF
GG

样例输出 2

0 1 1 1
0 0 1 1
0 0 0 1
0 0 0 0

代码解析

可以用笨办法,定义 bool 变量 k2, k8, k10, k16,当遇到不同范围字符,做好标记就可以

#include<iostream>
#include<string>
using namespace std;
void check(string s) {
bool k2=1, k8=1, k10=1, k16=1;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= '2' && s[i] <= '9' || s[i] >= 'A')
k2 = 0;
if (s[i] >= '8' && s[i] <= '9' || s[i] >= 'A')
k8 = 0;
if (s[i] >= 'A')
k10 = 0;
if (s[i] >= 'G')
k16 = 0;
}
cout << k2 << ' ' << k8 << ' ' << k10 << ' ' << k16 << endl;
}
int main() {
int n;
cin >> n;
while (n--) {
string s;
cin >> s;
check(s);
}
return 0;
}

202306-1 春游#

题目描述

老师带领同学们春游。已知班上有 NN 位同学,每位同学有从 00N1N-1 的唯一编号。到了集合时间,老师确认是否所有同学都到达了集合地点,就让同学们报出自己的编号。到达的同学都会报出自己的编号,不会报出别人的编号,但有的同学很顽皮,会多次报出。你能帮老师找出有哪些同学没有到达吗 ?。

输入格式

输入包含 22 行。第一行包含两个整数 NNMM,表示班级有 NN 位同学,同学们共有 MM 次报出编号。约定 2N,M10002 \le N,M \le 1000。 第二行包含 MM 个整数,分别为 MM 次报出的编号。约定所有编号是小于 NN 的非负整数。

输出格式

输出一行。如果所有同学都到达,则输出 NN;否则由小到大输出所有未到达的同学编号,空格分隔。

样例输入 1

3 3
0 2 1

样例输出 1

3

样例输入 2

3 5
0 0 0 0 0

样例输出 2

1 2

代码解析

使用数组来标记已经报过数的同学编号,每次报数 n,我们就将 student[n] 标记为 1

需要一个 bool 变量 all 来标记是否全部到达

#include<iostream>
using namespace std;
bool student[1001];
int main() {
int N, M, n;
cin >> N >> M;
for (int i = 0; i < M; i++) {
cin >> n;
student[n] = 1;
}
bool all = true;
for (int i = 0; i < N; i++) {
if (!student[i]) {
cout << i << ' ';
all = false;
}
}
if (all) cout << N;
return 0;
}

202306-2 密码合规#

题目描述

网站注册需要有用户名和密码,编写程序以检查用户输入密码的有效性。合规的密码应满足以下要求 :。

  1. 只能由 az\texttt a \sim \texttt z 之间 2626 个小写字母、AZ\texttt A \sim \texttt Z 之间 2626 个大写字母、090 \sim 9 之间 1010 个数字以及 !@#$ 四个特殊字符构成。
  2. 密码最短长度 :6:6 个字符,密码最大长度 :12:12 个字符。
  3. 大写字母,小写字母和数字必须至少有其中两种,以及至少有四个特殊字符中的一个。

输入格式

输入一行不含空格的字符串。约定长度不超过 100100。该字符串被英文逗号分隔为多段,作为多组被检测密码。

输出格式

输出若干行,每行输出一组合规的密码。输出顺序以输入先后为序,即先输入则先输出。

样例输入 1

seHJ12!@,sjdkffH$123,sdf!@&12HDHa!,123&^YUhg@!

样例输出 1

seHJ12!@
sjdkffH$123

提示

【样例 1 解释】

输入被英文逗号分为了四组被检测密码:seHJ12!@sjdkffH$123sdf!@&12HDHa!123&^YUhg@!。其中 sdf!@&12HDHa! 长度超过 12 个字符,不合规;123&^YUhg@! 包含四个特殊字符之外的字符不合规。

代码解析

定义 check 函数来判断一个密码是否合规

check 函数中,定义 up, down, digit, chr 四个 bool 变量分别判断字符串中是否含有大写、小写、数字、特殊符号,遍历的过程中如果有就标记为 1,当全部遍历完成之后判断 up + low + digit >= 2 表示三个中至少有两个,再判断 chr 是否为真就可以

拼接分割密码的时候,注意最后一个密码不是以逗号 , 结尾的,所以最后需要再判断一下

#include<iostream>
#include<string>
using namespace std;
bool check(string s) {
bool up = 0, low = 0, digit = 0, chr = 0;
if (s.size() < 6 || s.size() > 12)
return false;
for (int i = 0; i < s.size(); i++) {
if (s[i] >= 'a' && s[i] <= 'z')
low = 1;
else if (s[i] >= 'A' && s[i] <= 'Z')
up = 1;
else if (s[i] >= '0' && s[i] <= '9')
digit = 1;
else if (s[i]=='!'||s[i]=='@'||s[i]=='#'||s[i]=='$')
chr = 1;
else
return false;
}
if (up + low + digit >= 2 && chr)
return true;
else
return false;
}
int main() {
string s, password = "";
cin >> s;
for (int i = 0; i < s.size(); i++) {
if (s[i] == ',') {
if (check(password))
cout << password << endl;
password = "";
} else {
password += s[i];
}
}
if (check(password))
cout << password << endl;
return 0;
}
GESP 2023年C++三级编程题解析
https://yezi.press/posts/gesp/gesp-cpp3-2023/
作者
Yezi 叶子
发布于
2023/12/01
许可协议
CC BY-NC-SA 4.0