Files
project1/第01课-数据类型与分支结构/数据类型-编程题-教师版.md

13 KiB
Raw Blame History

第3课编程题教师版

本课知识点覆盖表

核心知识点 GESP等级 对应课堂题
intlong long、数据范围与 1LL 一级必考 课堂1
double、整数除法、类型转换、格式化输出 一级必考 课堂2
char、ASCII 码、大小写转换、字母平移 一级/二级必考 课堂3
boolstring、字符与数字转换 一级/二级 课堂4

本课加强大小写转换和字母平移训练。字母平移均按英文字母表循环,即 Z 的下一个字母是 A

一、课堂练习4题

课堂1超大长方体体积【适中】

题目描述: 输入长方体的长、宽、高,输出体积。三个量都能用 int 保存,但乘积可能超过 int 范围。

输入格式: 输入三个正整数,依次表示长、宽和高。

输出格式: 长方体体积。

数据范围: 1≤a,b,c≤10^6,答案不超过 10^18

输入样例:

100000 100000 2

输出样例:

20000000000

解题思路:1LL*a*b*c 使第一次乘法就按 long long 计算。

参考代码:

#include <iostream>
using namespace std;

int main() {
    int a, b, c;
    cin >> a >> b >> c;
    long long volume = 1LL * a * b * c;
    cout << volume;
    return 0;
}

易错提醒: 只把结果变量写成 long long 不够,右侧的乘法也必须提前转换。

课堂2比赛平均分【适中】

题目描述: 输入三名选手的总分和比赛场数,分别输出三人的平均分,保留两位小数;最后输出最高平均分。

输入格式: 依次输入三名选手的总分和比赛场数。

输出格式: 第一行三个平均分;第二行最高平均分,均保留两位小数。

数据范围: 1≤n≤1000≤s1,s2,s3≤10000

输入样例:

25 20 29 3

输出样例:

8.33 6.67 9.67
9.67

解题思路:1.0*s/n 触发浮点除法,使用 fixedsetprecision(2)

参考代码:

#include <iostream>
#include <iomanip>
#include <algorithm>
using namespace std;

int main() {
    int s1, s2, s3, n;
    cin >> s1 >> s2 >> s3 >> n;
    double a = 1.0 * s1 / n;
    double b = 1.0 * s2 / n;
    double c = 1.0 * s3 / n;
    cout << fixed << setprecision(2);
    cout << a << " " << b << " " << c << "\n";
    cout << max(a, max(b, c));
    return 0;
}

易错提醒: double a=s1/n 仍会先做整数除法,小数已经丢失。

课堂3字母变身与平移【适中】

题目描述: 输入一个英文字母和整数 k。先把字母转换为相反大小写,再在保持新大小写的前提下向后循环平移 k 位。

输入格式: 输入一个英文字母和向后平移的位数。

输出格式: 转换并平移后的字母。

数据范围: 0≤k≤10^9

输入样例:

Y 3

输出样例:

b

解题思路: 大小写互转可利用 ASCII 差值;平移只需使用 k%26,公式为 (c-base+k)%26+base

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c;
    long long k;
    cin >> c >> k;
    if (c >= 'A' && c <= 'Z') c = c + ('a' - 'A');
    else c = c - ('a' - 'A');
    char base = (c >= 'a' && c <= 'z') ? 'a' : 'A';
    c = (c - base + k % 26) % 26 + base;
    cout << c;
    return 0;
}

易错提醒: 平移必须循环;不能直接输出 c+k,否则可能越过字母范围。

课堂4账号检查器【适中】

题目描述: 输入一个不含空格的字符串。若长度不少于 6且同时含有大写字母、小写字母和数字输出 YES,否则输出 NO

输入格式: 一个字符串。

输出格式: YESNO

数据范围: 字符串长度不超过 100。

输入样例:

Abc123

输出样例:

YES

解题思路: 用三个 bool 变量记录是否出现三类字符,遍历 string 后综合判断。

参考代码:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    cin >> s;
    bool upper = false, lower = false, digit = false;
    for (char c : s) {
        if (c >= 'A' && c <= 'Z') upper = true;
        else if (c >= 'a' && c <= 'z') lower = true;
        else if (c >= '0' && c <= '9') digit = true;
    }
    bool valid = s.size() >= 6 && upper && lower && digit;
    cout << (valid ? "YES" : "NO");
    return 0;
}

易错提醒: bool 只记录真假;三个条件必须同时满足,应使用 &&

二、课后作业3题

课后1小写转大写【简单】

题目描述: 输入一个小写字母,使用 ASCII 码运算转成大写字母。

输入格式: 一个小写字母。

输出格式: 对应的大写字母。

数据范围: az

输入样例:

g

输出样例:

G

解题思路: 小写字母比对应大写字母的 ASCII 码大 32计算 c-'a'+'A'

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c;
    cin >> c;
    cout << (char)(c - 'a' + 'A');
    return 0;
}

易错提醒: 字符常量必须使用单引号。

课后2数字字符还原【简单】

题目描述: 输入一个数字字符,输出它代表的整数再加 5 的结果。

输入格式: 输入一个范围为 09 的数字字符。

输出格式: 一个整数。

数据范围: '0'≤c≤'9'

输入样例:

7

输出样例:

12

解题思路: 使用 c-'0' 把数字字符转换成整数。

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c;
    cin >> c;
    int number = c - '0';
    cout << number + 5;
    return 0;
}

易错提醒: 直接计算 c+5 得到的是新的字符编码,不是题目需要的整数。

课后3整数平均数【简单】

题目描述: 输入两个整数,输出它们的平均数,保留一位小数。

输入格式: 输入两个整数。

输出格式: 平均数,保留一位小数。

数据范围: 两数绝对值不超过 10^6

输入样例:

2 5

输出样例:

3.5

解题思路:(a+b)/2.0 进行浮点除法。

参考代码:

#include <iostream>
#include <iomanip>
using namespace std;

int main() {
    int a, b;
    cin >> a >> b;
    cout << fixed << setprecision(1) << (a + b) / 2.0;
    return 0;
}

易错提醒: 除数写成 2 会进行整数除法,写成 2.0 才保留小数。

三、扩展练习7题

扩展1向后移动一位【基础综合】

题目描述: 输入一个小写字母,输出字母表中的下一个小写字母;z 的下一个字母为 a

输入格式: 一个小写字母。

输出格式: 平移后的字母。

数据范围: az

输入样例:

z

输出样例:

a

解题思路:(c-'a'+1)%26+'a' 实现循环。

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c;
    cin >> c;
    cout << (char)((c - 'a' + 1) % 26 + 'a');
    return 0;
}

易错提醒: 单独写 c+1 无法处理 z

扩展2双向字母平移【基础综合】

题目描述: 输入一个大写字母、方向 LR 和步数 k。向左或向右循环平移,输出结果。

输入格式: 依次输入一个大写字母、平移方向和移动位数。

输出格式: 平移后的大写字母。

数据范围: 0≤k≤10^9

输入样例:

B L 3

输出样例:

Y

解题思路: 右移加 k;左移等价于加 26-k%26

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c, direction;
    long long k;
    cin >> c >> direction >> k;
    k %= 26;
    if (direction == 'L') k = (26 - k) % 26;
    cout << (char)((c - 'A' + k) % 26 + 'A');
    return 0;
}

易错提醒: C++ 中负数取模可能仍为负数,所以左移时先转成非负偏移量。

扩展3两个字母的距离【中等】

题目描述: 输入两个同为大写的字母,输出从第一个字母向后循环移动到第二个字母所需的最少步数。

输入格式: 输入两个大写字母。

输出格式: 向后平移步数。

数据范围: AZ

输入样例:

X C

输出样例:

5

解题思路: 计算 (b-a+26)%26

参考代码:

#include <iostream>
using namespace std;

int main() {
    char a, b;
    cin >> a >> b;
    cout << (b - a + 26) % 26;
    return 0;
}

易错提醒: 加 26 是为了避免结果为负数。

扩展4字母镜像【中等】

题目描述: 字母表两端互为镜像:A↔ZB↔Y,小写字母同理。输入一个字母,输出它的镜像字母,并保持大小写。

输入格式: 一个英文字母。

输出格式: 镜像字母。

数据范围: 英文字母。

输入样例:

C

输出样例:

X

解题思路: 大写字母镜像为 'A'+'Z'-c,小写同理。

参考代码:

#include <iostream>
using namespace std;

int main() {
    char c;
    cin >> c;
    if (c >= 'A' && c <= 'Z') cout << (char)('A' + 'Z' - c);
    else cout << (char)('a' + 'z' - c);
    return 0;
}

易错提醒: 大写和小写必须使用各自的范围计算。

扩展5凯撒口令【中等】

题目描述: 输入一个不含空格的字符串和非负整数 k。所有英文字母向后循环平移 k 位,保持大小写;数字和符号不变。

输入格式: 第一行输入一个不含空格的字符串;第二行输入向后平移的位数。

输出格式: 平移后的字符串。

数据范围: 字符串长度不超过 1000≤k≤10^9

输入样例:

Az-9
2

输出样例:

Cb-9

解题思路: 根据字符范围选择基准 'A''a';其他字符原样保留。

参考代码:

#include <iostream>
#include <string>
using namespace std;

int main() {
    string s;
    long long k;
    cin >> s >> k;
    k %= 26;
    for (char &c : s) {
        if (c >= 'A' && c <= 'Z')
            c = (c - 'A' + k) % 26 + 'A';
        else if (c >= 'a' && c <= 'z')
            c = (c - 'a' + k) % 26 + 'a';
    }
    cout << s;
    return 0;
}

易错提醒: 平移后必须写回字符串;数字和符号不能参与字母公式。

扩展6最短平移方向【略难】

题目描述: 输入两个大写字母。求从第一个字母循环平移到第二个字母的最少步数;若向左和向右步数相同,输出 BOTH,否则输出 LEFTRIGHT,并输出步数。

输入格式: 输入两个大写字母。

输出格式: 方向和最少步数。

数据范围: AZ

输入样例:

A X

输出样例:

LEFT 3

解题思路: 右移步数为 (b-a+26)%26,左移步数为 (a-b+26)%26,比较两者。

参考代码:

#include <iostream>
using namespace std;

int main() {
    char a, b;
    cin >> a >> b;
    int right = (b - a + 26) % 26;
    int left = (a - b + 26) % 26;
    if (left < right) cout << "LEFT " << left;
    else if (right < left) cout << "RIGHT " << right;
    else cout << "BOTH " << left;
    return 0;
}

易错提醒: 两个字母相同也属于左右步数相同,此时输出 BOTH 0

扩展7解密未知平移量【略难】

题目描述: 某个大写字母经过向后循环平移变成另一个大写字母。输入原字母和结果字母,求 025 范围内唯一的平移量 k;再输入第三个大写字母,按同样规则平移并输出。

输入格式: 依次输入原字母、加密后的字母和需要继续加密的字母。

输出格式: 第一行平移量 k;第二行第三个字母平移后的结果。

数据范围: AZ

输入样例:

Y B Z

输出样例:

3
C

解题思路: 先由前两个字母计算 k=(encoded-original+26)%26,再把 k 应用于第三个字母。

参考代码:

#include <iostream>
using namespace std;

int main() {
    char original, encoded, target;
    cin >> original >> encoded >> target;
    int k = (encoded - original + 26) % 26;
    char answer = (target - 'A' + k) % 26 + 'A';
    cout << k << "\n" << answer;
    return 0;
}

易错提醒: 计算平移量和应用平移量使用的是同一个循环公式。