2024 年 9 月青少年软编等考 C 语言二级真题解析

目录

  • T1. 火中取栗
    • 思路分析
  • T2. 垃圾分类
    • 思路分析
  • T3. 生成字母串
    • 思路分析
  • T4. B 是 A 的多少倍
    • 思路分析
  • T5. 机器人拼图
    • 思路分析

T1. 火中取栗

据法国诗人拉 · 封丹的寓言《猴子与猫》里说,猴子骗猫取火中的栗子,结果取出后被猴子吃了,猫却因此被烧掉了爪上的毛。

现在我们有 n n n 只炉子,每只炉子里烤着一些栗子。假设笨猫每次伸爪最多能从一只炉子里抓出 k k k 颗栗子,但会被烧掉 1 1 1 撮毛。问笨猫抓出所有的栗子最少要被烧掉多少撮毛?

时间限制:1 s
内存限制:64 MB

  • 输入
    输入在第一行中给出 2 2 2 个正整数 n n n ≤ 100000 ≤ 100000 100000)和 k k k ≤ 10 ≤ 10 10),含义如题面所述。数字间以空格分隔。
    随后一行给出 n n n 个不超过 1000 1000 1000 的正整数,其中第 i i i 个数字表示第 i i i 只炉子里烤的栗子的数量。
  • 输出
    在一行中输出笨猫抓出所有的栗子最少要被烧掉多少撮毛。
  • 样例输入
    5 2
    3 4 8 1 15
    
  • 样例输出
    17
    

思路分析

此题考查循环结构,属于入门题。

循环遍历每一个炉子中的栗子数量 x x x,计算小猫需要取栗子的次数 ⌈ x / k ⌉ \lceil x/k \rceil x/k,并将每一个炉子中需要取栗子的次数累加即可。

/*
 * Name: T1.cpp
 * Problem: 火中取栗
 * Author: Teacher Gao.
 * Date&Time: 2025/01/15 23:34
 */

#include 

using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, k, x, tot = 0;
    cin >> n >> k;
    for (int i = 1; i <= n; i++) {
        cin >> x;
        tot += (x + k - 1) / k;
    }

    cout << tot << endl;

    return 0;
}

T2. 垃圾分类

据香港《南华早报》7 月 15 日文章,上海严格的垃圾分类新规令不少居民抓狂。这催生出大量帮助找出正确分类答案的 App 和小程序。目前仅微信上就至少有 280 280 280 种与垃圾处理有关的 App,在苹果应用商店也达 130 130 130 种。支付宝表示,已有 60 60 60 多家独立 App 开发商申请为该平台提供类似服务。

本题就请你现场实现一个简单的垃圾分类小助手。

时间限制:1 s
内存限制:64 MB

  • 输入
    输入首先给出官方分类指南中每种物品的归属。在一行中给出一个正整数 N N N ≤ 100000 ≤ 100000 100000),即物品数量;
    随后 N N N 行,每行给出一个物品名称(长度不超过 10 10 10 的、由小写英文字母和下划线组成的字符串)和该物品所属的分类( 1 1 1 代表干垃圾、 2 2 2 代表湿垃圾、 3 3 3 代表可回收物、 4 4 4 代表有害垃圾)。题目保证所有物品名称无重复。
    随后每行给出一个查询物品的名称(格式与指南物品名称相同)。
    最后一行给出结束符 #,表示查询终止,这一行不需要查询。(查询的数量 ≤ 100000 ≤ 100000 100000 个)
  • 输出
    对每个查询的物品,在一行中给出其所属分类:Gan laji 代表干垃圾;Shi laji 代表湿垃圾;Ke Hui Shou 代表可回收物;You Hai laji 代表有害垃圾。如果查询的物品不在指南中,则输出 ? 表示不知道。
  • 样例输入
    4
    bao_zhi 3
    dian_chi 4
    dan_ke 2
    bei_ke 1
    dan_ke
    dian_chi
    ren_zha
    bao_zhi
    bei_ke
    #
    
  • 样例输出
    Shi laji
    You Hai laji
    ?
    Ke Hui Shou
    Gan laji
    

思路分析

此题考查字符串查找与 m a p map map,属于基础题。

此题如果采用顺序查找,时间复杂度为 KaTeX parse error: Undefined control sequence: \cal at position 1: \̲c̲a̲l̲{O}(n^2),对于 1 0 5 10^5 105 的数据量,是无法在 1   s 1\ s 1 s 内完成的,因此务必使用 m a p map map u n o r d e r e d _ m a p unordered\_map unordered_map。为了便于映射,减少分支判断,我们用一个 s t r i n g string string 数组存储 1 ∼ 4 1\sim 4 14 对应的垃圾类别。对于输入的垃圾分类表,用 m a p map map 来完成存储,为了代码简洁,可以直接将垃圾映射到对应类别的字符串上,而不是那个整数。之后进行不定项输入查询即可。

/*
 * Name: T2.cpp
 * Problem: 垃圾分类
 * Author: Teacher Gao.
 * Date&Time: 2025/01/15 23:44
 */

#include 

using namespace std;

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n, p;
    string x, h[] = {"", "Gan laji",
                         "Shi laji",
                         "Ke Hui Shou",
                         "You Hai laji"};
    map<string, string> mp;

    cin >> n;
    for (int i = 1; i <= n; i++) {
        cin >> x >> p;
        mp[x] = h[p];
    }

    while (cin >> x && x != "#") {
        if (mp.find(x) != mp.end()) {
            cout << mp[x] << "\n";
        }
        else {
            cout << "?\n";
        }
    }

    return 0;
}

T3. 生成字母串

英语老师要求学生按照如下规则写一串字母:

  • 如果写了某个大写字母,下一个就必须写同个字母的小写,或者写字母表中下一个字母的大写;
  • 如果写了某个小写字母,下一个就必须写同个字母的大写,或者写字母表中前一个字母的小写。

例如 aAaABCDdcbBC 就是一个合法的字母串;而 dEFfeFGhI 就是非法的。

本题就请你编写程序,自动生成一个合法的字母串。

时间限制:1 s
内存限制:64 MB

  • 输入
    输入在第一行给出一个不超过 10000 10000 10000 的正整数 N N N 和第一个字母。
    随后一行给出一个由 01 组成的长度为 N N N 的字符串。这个串给出了字母串的生成规则:从第一个字母开始,如果对应的规则串字符是 0,则下一个字母应该生成当前字母的大 / 小写;如果是 1 则下一个字母应该生成当前字母的前 / 后一个字母。
    注意:因为字母表中 a 没有前一个字母,Z 没有后一个字母,所以如果此时遇到 1 就忽略之。
  • 输出
    在一行中输出按规则生成的字母串。如果有多个答案,输出任意一个即可。
  • 样例输入
    12 a
    001011101101
    
  • 样例输出
    aAaABCDdcbBC
    

思路分析

此题考查字符串遍历,属于入门题。

依次遍历给定的 01 01 01 串,从给定的起始字母开始,按照题目要求进行模拟即可。

/*
 * Name: T3.cpp
 * Problem: 生成字母串
 * Author: Teacher Gao.
 * Date&Time: 2025/01/15 23:57
 */

#include 

using namespace std;

int main()
{
    int n;
    string s, t;

    cin >> n >> s >> t;
    for (int i = 0; i < n; i++) {
        if (t[i] == '0') {
            if (s.back() <= 'Z') s.push_back(s.back() + 32);
            else s.push_back(s.back() - 32);
        }
        else {
            if (s.back() != 'a' && s.back() != 'Z')
                s.push_back(s.back() + 1);
        }
    }

    cout << s << endl;

    return 0;
}

T4. B 是 A 的多少倍

设一个数 A A A 的最低 D D D 位形成的数是 a d ad ad。如果把 a d ad ad 截下来移到 A A A 的最高位前面,就形成了一个新的数 B B B B B B A A A 的多少倍?例如将 12345 12345 12345 的最低 2 2 2 45 45 45 截下来放到 123 123 123 的前面,就得到 45123 45123 45123,它约是 12345 12345 12345 3.66 3.66 3.66 倍。

时间限制:1 s
内存限制:64 MB

  • 输入
    输入在一行中给出一个正整数 A A A ≤ 1 0 9 ≤ 10^9 109)和要截取的位数 D D D。题目保证 D D D 不超过 A A A 的总位数。
  • 输出
    计算 B B B A A A 的多少倍,输出小数点后 2 2 2 位。
  • 样例输入 1
    12345 2
    
  • 样例输出 1
    3.66
    
  • 样例输入 2
    12345 5
    
  • 样例输出 2
    1.00
    

思路分析

此题考查循环结构和数位分离,属于入门题。

首先通过数位分离计算出 A A A 的位数 n n n,然后计算第 D D D 位(从 0 0 0 开始,下同)的位权 p p p,方便取出低 D D D 位和高 n − D n-D nD 位。为了便于计算数字 B B B,可以求出第 n − D n-D nD 位的位权 q q q,由此可以计算出 B = A % p ∗ q + A / p B=A\%p*q + A/p B=A%pq+A/p。然后计算 1.0 * B / A 即可。

/*
 * Name: T4.cpp
 * Problem: B 是 A 的多少倍
 * Author: Teacher Gao.
 * Date&Time: 2025/01/16 00:17
 */

#include 

using namespace std;

int main()
{
    int A, d;
    cin >> A >> d;

    int t = A, n = 0;
    while (t) {
        t /= 10;
        n++;
    }
    int p = pow(10, d), q = pow(10, n-d);
    int B = A % p * q + A / p;

    printf("%.2f\n", 1.0  * B / A);

    return 0;
}

T5. 机器人拼图

给定一块由 n × m n × m n×m 个格子组成的矩形拼图板,本题要求你根据给定的机械手移动指令集,将拼图中的碎片逐一放到指定位置。

机械手每次抓取一块碎片,都会在拼图板的左上角位置等待指令。一个指令集是由 0 ∼ 4 0\sim 4 04 这五个数字组成的字符串,每个数字代表的意义如下:

  • 1 1 1:向右移动一格;
  • 2 2 2:向下移动一格;
  • 3 3 3:向左移动一格;
  • 4 4 4:向上移动一格;
  • 0 0 0:将碎片放置在当前位置,并结束这次任务。

如果指令要求机械手移动到拼图板边界外,机械手会无视这个指令。如果接收到指令 0 0 0 时,当前位置上已经有一块碎片放好了,机械手会扔掉手里的碎片,结束这次任务。

时间限制:1 s
内存限制:64 MB

  • 输入
    输入第一行给出 2 2 2 个正整数 n n n m m m 1 ≤ n , m ≤ 100 1 ≤ n,m ≤ 100 1n,m100),随后一共有 n × m n × m n×m 行,第 i i i 行给出编号为 i i i i = 1 , . . . n × m i=1,... n×m i=1,...n×m)的碎片对应的指令集,每条指令集一定以唯一的 0 0 0 结尾。(总的指令操作步数不超过 1 0 7 10^7 107
  • 输出
    输出 n n n 行,每行 m m m 个整数,为放置在对应位置上的碎片编号。如果该位置上没有碎片,则输出 0 0 0。一行中的数字间以 1 1 1 个空格分隔,行首位不得有多余空格。
  • 样例输入
    2 3
    1120
    21140
    34120
    0
    110
    21111340
    
  • 样例输出
    4 6 2
    0 3 1
    

思路分析

此题考查二维数组与模拟法,属于基础题。

为了便于前进或转向,我们定义两个增量数组 d x , d y dx,dy dx,dy,分别表示横坐标和纵坐标增量,这样我们就可以用 x + dx[s[j]-'0'], y + dy[s[j]-'0'] 计算从 ( x , y ) (x,y) (x,y) 前进或转向后的新坐标 ( n x , n y ) (nx, ny) (nx,ny),如果该坐标没有越界,则更新 ( x , y ) (x,y) (x,y) ( n x , n y ) (nx, ny) (nx,ny),移动结束后检测 ( x , y ) (x,y) (x,y) 处如果没有拼图,则将当前拼图放进去。最后输出这个二维数组即可。

/*
 * Name: T5.cpp
 * Problem: 机器人拼图
 * Author: Teacher Gao.
 * Date&Time: 2025/01/17 15:42
 */

#include 

using namespace std;

int main()
{
    int n, m;
    string s;
    int a[105][105] = {0};
    int dx[] = {0, 0, 1,  0, -1};
    int dy[] = {0, 1, 0, -1,  0};

    cin >> n >> m;
    for (int i = 1; i <= n*m; i++) {
        cin >> s;
        int x = 1, y = 1, nx, ny;
        for (int j = 0; j < s.size()-1; j++) {
            nx = x + dx[s[j] - '0'];
            ny = y + dy[s[j] - '0'];
            if (nx < 1 || nx > n || ny < 1 || ny > m) continue;
            x = nx, y = ny;
        }
        if (!a[x][y]) a[x][y] = i;
    }

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= m; j++) {
            cout << a[i][j] << " ";
        }
        cout << "\n";
    }

    return 0;
}

你可能感兴趣的:(青少年软编等考,C,语言题解集(二级),c语言,开发语言,算法,学习,青少年编程,题解,C++)