【GESP】C++四级真题 luogu-B3850 [GESP202306 四级] 幸运数
GESP C++四级真题,函数应用练习,难度⭐⭐★☆☆。
luogu-B3850 [GESP202306 四级] 幸运数
题目要求
题目描述
小明发明了一种 “幸运数”。一个正整数,其偶数位不变(个位为第 $1$ 位,十位为第 $2$ 位,以此类推),奇数位做如下变换:将数字乘以 $7$,如果不大于 $9$ 则作为变换结果,否则把结果的各位数相加,如果结果不大于 $9$ 则作为变换结果,否则(结果仍大于 $9$)继续把各位数相加,直到结果不大于 $9$,作为变换结果。变换结束后,把变换结果的各位数相加,如果得到的和是 $8$ 的倍数,则称一开始的正整数为幸运数。
例如,$16347$:第 $1$ 位为 $7$,乘以 $7$ 结果为 $49$,大于 $9$,各位数相加为 $13$,仍大于 $9$,继续各位数相加,最后结果为 $4$;第 $3$ 位为 $3$,变换结果为 $3$;第 $5$ 位为 $1$,变换结果为 $7$。最后变化结果为 $76344$,对于结果 $76344$ 其各位数之和为 $24$,是 $8$ 的倍数。因此 $16347$ 是幸运数。
输入格式
输入第一行为正整数 $N$,表示有 $N$ 个待判断的正整数。约定 $1 \le N \le 20$。
从第 $2$ 行开始的 $N$ 行,每行一个正整数,为待判断的正整数。约定这些正整数小于 $10^{12}$。
输出格式
输出 $N$ 行,对应 $N$ 个正整数是否为幸运数,如是则输出 ‘T’,否则输出 ‘F’。
提示:不需要等到所有输入结束在依次输出,可以输入一个数就判断一个数并输出,再输入下一个数。
输入输出样例 #1
输入 #1
1
2
3
2
16347
76344
输出 #1
1
2
T
F
题目分析
1. 理解题目要求
这道题要求我们判断一个数是不是”幸运数”。一个数要成为幸运数需要满足以下条件:
- 对数字的奇数位(从右往左数,个位是第1位)进行特殊变换
- 偶数位保持不变
- 最后把所有数位加起来,如果是8的倍数就是幸运数
2. 关键函数实现
我们的代码主要包含三个重要的函数:
- 计算数位和的函数
sum_digit
- 输入一个数 $x$
- 计算公式:$sum = d_1 + d_2 + … + d_n$ (其中 $d_i$ 是 $x$ 的每一位数字)
- 比如:$sum_digit(123) = 1 + 2 + 3 = 6$
- 数字变换函数
trans_num
- 输入一个数字 $x$
- 先计算 $7x$
- 如果结果大于9,就不断把各位数字相加,直到结果不大于9
- 比如:$trans_num(7) = 49 \rightarrow 4+9=13 \rightarrow 1+3=4$
- 判断幸运数的函数
is_lucky_num
- 从右往左处理每一位数字
- 奇数位用
trans_num
变换 - 偶数位保持不变
- 最后判断所有数位之和是否能被8整除
3. 代码实现方式
我们提供了两种实现方法:
- 数字处理方法
- 直接对数字进行运算
- 使用除法和取余来获取每一位数字
- 优点是不需要额外空间
- 字符串处理方法
- 把数字转成字符串
- 直接访问每一位数字
- 更容易理解和操作
两种方法都可以解决问题,选择你觉得更容易理解的方法即可。
4. 举个例子
以数字16347为例:
- 从右往左看,第1、3、5位(7、3、1)需要变换
- 7变成4,3不变,1变成7
- 变换后得到76344
- 7+6+3+4+4=24,是8的倍数
- 所以16347是幸运数
示例代码
方法一:数字处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <iostream>
/**
* 计算一个数字各位数字之和
* @param num 待计算的数字
* @return 各位数字之和
*/
int sum_digit(int num) {
int sum = 0; // 存储各位数字之和
while (num != 0) {
sum += num % 10; // 取出最后一位数字并累加
num /= 10; // 去掉最后一位数字
}
return sum;
}
/**
* 对数字进行变换处理
* 将数字乘以7,如果结果大于9,则将各位数字相加直到结果不大于9
* @param num 待变换的数字
* @return 变换后的结果(保证结果不大于9)
*/
int trans_num(int num) {
int sum = num * 7; // 先将数字乘以7
while(sum > 9) { // 如果结果大于9,继续处理
sum = sum_digit(sum); // 计算各位数字之和
}
return sum;
}
/**
* 判断一个数是否为幸运数
* 幸运数的定义:将奇数位的数字进行变换后,所有位数字之和是8的倍数
* @param num 待判断的数字
* @return true表示是幸运数,false表示不是幸运数
*/
bool is_lucky_num(long long num) {
int sum = 0; // 记录所有位数字之和
int idx = 0; // 记录当前处理的是第几位
while (num != 0) {
// 取出最后一位数字
int c_num = num % 10;
// 如果是奇数位(从右往左数,从0开始),进行变换
if (idx % 2 == 0) {
c_num = trans_num(c_num);
}
sum += c_num; // 累加当前位的数字
num /= 10; // 去掉最后一位
idx++; // 位数加1
}
// 判断和是否是8的倍数
if (sum % 8 == 0) {
return true;
}
return false;
}
int main() {
int n; // 待处理的数字个数
std::cin >> n;
// 循环处理每个数字
for (int i = 0; i < n; i++) {
long long number; // 当前要判断的数字
std::cin >> number;
// 判断并输出结果
if (is_lucky_num(number)) {
std::cout << 'T' << "\n";
} else {
std::cout << 'F' << "\n";
}
}
return 0;
}
方法二: 字符串处理
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
#include <iostream>
#include <string>
/**
* 计算一个数字各位数字之和
* @param num 待计算的数字
* @return 各位数字之和
*/
int sum_digit(int num) {
int sum = 0; // 存储各位数字之和
while (num != 0) {
sum += num % 10; // 取出最后一位数字并累加
num /= 10; // 去掉最后一位数字
}
return sum;
}
/**
* 对数字进行变换处理
* 将数字乘以7,如果结果大于9,则将各位数字相加直到结果不大于9
* @param num 待变换的数字
* @return 变换后的结果(保证结果不大于9)
*/
int trans_num(int num) {
int sum = num * 7; // 先将数字乘以7
while(sum > 9) { // 如果结果大于9,继续处理
sum = sum_digit(sum); // 计算各位数字之和
}
return sum;
}
/**
* 判断一个数是否为幸运数
* @param num 待判断的数字
* @return true表示是幸运数,false表示不是幸运数
* 判断规则:
* 1. 将数字转换为字符串处理
* 2. 对奇数位(从右往左,从0开始)进行变换
* 3. 计算所有位数字之和
* 4. 判断和是否是8的倍数
*/
bool is_lucky_num(long long num) {
// 将数字转换为字符串便于处理
std::string num_str = std::to_string(num);
// 记录所有位数字之和
int sum = 0;
// 从右往左遍历每一位
for (int i = 0; i < num_str.length(); i++) {
// 处理奇数位(从右往左数,从0开始)
if (i % 2 == 0) {
// 将字符转换为数字
int c_num = num_str[num_str.length() -1 -i] - '0';
// 进行变换
c_num = trans_num(c_num);
// 将变换后的数字转回字符
num_str[num_str.length() -1 -i] = char(c_num + '0');
}
// 累加当前位的数字
sum += num_str[num_str.length() -1 -i] - '0';
}
// 判断和是否是8的倍数
if (sum % 8 == 0) {
return true;
}
return false;
}
int main() {
// 读入待处理的数字个数
int n;
std::cin >> n;
// 循环处理每个数字
for (int i = 0; i < n; i++) {
// 读入当前要判断的数字
long long number;
std::cin >> number;
// 判断并输出结果
if (is_lucky_num(number)) {
std::cout << 'T' << "\n";
} else {
std::cout << 'F' << "\n";
}
}
return 0;
}
所有代码已上传至Github:https://github.com/lihongzheshuai/yummy-code
GESP各级别考纲、真题讲解、知识拓展和练习清单等详见【置顶】【GESP】C++ 认证学习资源汇总
“luogu-”系列题目已加入洛谷Java、C++初学团队,作业清单,可在线评测,团队名额有限。
“bcqm-”系列题目可在编程启蒙题库进行在线评测。
欢迎加入:Java、C++、Python技术交流QQ群(982860385),大佬免费带队,有问必答
欢迎加入:C++ GESP/CSP认证学习QQ频道,考试资源总结汇总
欢迎加入:C++ GESP/CSP学习交流QQ群(688906745),考试认证学员交流,互帮互助