文章

【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. 对数字的奇数位(从右往左数,个位是第1位)进行特殊变换
  2. 偶数位保持不变
  3. 最后把所有数位加起来,如果是8的倍数就是幸运数

2. 关键函数实现

我们的代码主要包含三个重要的函数:

  1. 计算数位和的函数 sum_digit
    • 输入一个数 $x$
    • 计算公式:$sum = d_1 + d_2 + … + d_n$ (其中 $d_i$ 是 $x$ 的每一位数字)
    • 比如:$sum_digit(123) = 1 + 2 + 3 = 6$
  2. 数字变换函数 trans_num
    • 输入一个数字 $x$
    • 先计算 $7x$
    • 如果结果大于9,就不断把各位数字相加,直到结果不大于9
    • 比如:$trans_num(7) = 49 \rightarrow 4+9=13 \rightarrow 1+3=4$
  3. 判断幸运数的函数 is_lucky_num
    • 从右往左处理每一位数字
    • 奇数位用 trans_num 变换
    • 偶数位保持不变
    • 最后判断所有数位之和是否能被8整除

3. 代码实现方式

我们提供了两种实现方法:

  1. 数字处理方法
    • 直接对数字进行运算
    • 使用除法和取余来获取每一位数字
    • 优点是不需要额外空间
  2. 字符串处理方法
    • 把数字转成字符串
    • 直接访问每一位数字
    • 更容易理解和操作

两种方法都可以解决问题,选择你觉得更容易理解的方法即可。

4. 举个例子

以数字16347为例:

  1. 从右往左看,第1、3、5位(7、3、1)需要变换
  2. 7变成4,3不变,1变成7
  3. 变换后得到76344
  4. 7+6+3+4+4=24,是8的倍数
  5. 所以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),考试认证学员交流,互帮互助

GESP/CSP 认证学习微信公众号
GESP/CSP 认证学习微信公众号
本文由作者按照 CC BY 4.0 进行授权