2025蓝桥杯C++青少组省赛 所有题题解

题目传送门:

1.B4375 [蓝桥杯青少年组省赛 2025] 庆典队列

2.B4376 [蓝桥杯青少年组省赛 2025] 茶具套装

3.B4377 [蓝桥杯青少年组省赛 2025] 平衡奇偶位置的字符交换

4.B4378 [蓝桥杯青少年组省赛 2025] 矩阵圈层 90 度交错旋转

5.B4379 [蓝桥杯青少年组省赛 2025] 硬币游戏

6.B4380 [蓝桥杯青少年组省赛 2025] 魔术扑克牌排列

题目一:

题目描述

有 n 名志愿者参加了一场庆典活动,我们希望将这些人排成一个矩形队列,要求队列共有 A 行,且每一行的人数都要相等。

请计算每一行最多有多少名志愿者。

注意:不一定要将所有的志愿者都安排进队列。

例如:n=50,A=11,表示要将 50 名志愿者排成一个 11 行的矩形队列,那么每一行最多能安排 4 名志愿者。

输入格式

输入两个整数 n 和 A(2≤n≤500,2≤A≤n),分别表示志愿者人数以及矩形队列的行数,整数之间以一个空格隔开。

输出格式

输出一个整数,表示矩形队列的每一行最多有多少名志愿者。

输入输出样例

输入 #1复制

50 11

输出 #1复制

4

这道题没什么好说的,直接上代码:

#include<bits/stdc++.h>
using namespace std;
int n,m;
int main(){
	cin>>n>>m;
	cout<<n/m;
	return 0;
}

第二题:

题目描述

佳佳在一家茶具商店工作,有客户要订购一些茶具套装,一套完整的茶具套装包含 1 个茶壶、1 个盖碗、1 个茶漏以及 4 个茶杯。现在已知茶壶、盖碗、茶漏和茶杯各自的数量,需要编写一个程序来计算最多能够组成多少套完整的茶具套装。

例如:茶壶、盖碗、茶漏和茶杯各自的数量分别是 3,4,2,13。根据这些茶具的数量,佳佳最多能组成 2 套完整的茶具套装。

输入格式

输入 4 个整数(0≤ 整数 ≤100),分别表示茶壶、盖碗、茶漏和茶杯各自的数量,整数之间以一个空格隔开。

输出格式

输出一个整数,表示最多能组成完整的茶具套装数量。

输入输出样例

输入 #1复制

3 4 2 13

输出 #1复制

2

这道题也很简单,直接上代码:

#include<bits/stdc++.h>
using namespace std;
int a,b,c,d;
int a1,b1,c1,d1;
int main(){
    cin>>a>>b>>c>>d;
    a1=a;
    b1=b;
    c1=c;
    d1=d/4;
    int maxx=min(min(min(a1,b1),c1),d1);
	cout<<maxx;
    return 0;
}

第三题:

题目描述

给定一个字符串 S,其中仅包含字符 A 和字符 B。你每次可以选择交换两个位置相邻的字符,请计算如果要使奇数位置上(位置从 1 开始)字符 A 的数量等于偶数位置上字符 A 的数量,最少需要进行多少次交换操作。

例如:S=AABABA,从左往右数,奇数位置上字符 A 的数量为 1(位置 1),偶数位置上字符 A 的数量为 3(位置 2、4、6)。可将位置 2 的字符 A 和位置 3 的字符 B 交换。交换后,奇数位置上字符 A 的数量和偶数位置上字符 A 的数量都为 2,满足题目要求,故最少需要交换一次。

输入格式

输入一个字符串 S(2≤S 的长度 ≤105),其中仅包含字符 A 和字符 B。

输出格式

输出一个整数,表示满足题目要求的最少交换次数,如果无论怎么交换都无法满足题目要求,则输出 −1。

输入输出样例

输入 #1复制

AABABA

输出 #1复制

1

这道题我在考场上的时候TLE了,最后没有时间改,然后只对了15%,太恶心了。于是,我今天攻下了这道题,题解:

题目分析

这道题目要求我们通过相邻交换操作,使得字符串中奇数位置上的A的数量等于偶数位置上的A的数量。我们需要计算达成这一目标所需的最少交换次数。

关键观察

  1. 奇偶位置A的数量关系:首先需要统计原始字符串中奇数位置和偶数位置上A的数量。

  2. 可行性判断:只有当总A的数量为偶数时才可能有解,否则输出-1。

  3. 交换策略:当奇数位置A的数量少于偶数位置时,我们需要将偶数位置的A移动到奇数位置;反之则相反。

解题思路

  1. 统计A的数量:分别统计奇数位置和偶数位置上的A的数量。

  2. 可行性检查:如果总A数量为奇数,直接返回-1。

  3. 计算目标值:目标是将奇数位置和偶数位置的A数量都调整为总A数量的一半。

  4. 计算交换次数

    • 当奇数位置A不足时,找到需要移动到奇数位置的A的位置

    • 计算将这些A移动到目标奇数位置所需的交换次数总和

代码实现

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

int minSwaps(string s) {
    int n = s.length();
    int oddA = 0, evenA = 0;
    
    // 统计奇数位和偶数位的A数量(位置从1开始)
    for (int i = 0; i < n; i++) {
        if (s[i] == 'A') {
            if ((i + 1) % 2 == 1) oddA++;
            else evenA++;
        }
    }
    
    int totalA = oddA + evenA;
    if (totalA % 2 != 0) return -1;
    
    int target = totalA / 2;
    int diff = oddA - target;
    
    if (diff == 0) return 0;
    
    // 需要移动的A数量
    int moveCount = abs(diff);
    int swaps = 0;
    vector<int> positions;
    
    // 收集需要移动的A的位置
    if (diff > 0) { // 奇数位A过多,需要移动到偶数位
        for (int i = 0; i < n && positions.size() < moveCount; i++) {
            if (s[i] == 'A' && (i + 1) % 2 == 1) {
                positions.push_back(i);
            }
        }
    } else { // 偶数位A过多,需要移动到奇数位
        for (int i = 0; i < n && positions.size() < moveCount; i++) {
            if (s[i] == 'A' && (i + 1) % 2 == 0) {
                positions.push_back(i);
            }
        }
    }
    
    // 计算交换次数
    for (int i = 0; i < moveCount; i++) {
        int currentPos = positions[i];
        int targetPos;
        
        if (diff > 0) { // 奇数位A移动到最近的偶数位
            targetPos = currentPos + (currentPos % 2 == 0 ? 1 : -1);
        } else { // 偶数位A移动到最近的奇数位
            targetPos = currentPos + (currentPos % 2 == 0 ? -1 : 1);
        }
        
        // 确保目标位置有效
        if (targetPos < 0 || targetPos >= n) {
            // 如果无法交换(边界情况),可能需要更复杂的处理
            return -1;
        }
        
        swaps += abs(currentPos - targetPos);
        // 模拟交换(实际不需要真正交换,因为我们只计算次数)
    }
    
    return swaps;
}

int main() {
    string s;
    cin >> s;
    cout << minSwaps(s) << endl;
    return 0;
}

代码解释

  1. 统计A的位置:使用两个数组oddAevenA分别记录奇数位置和偶数位置上A的索引。

  2. 可行性检查:如果总A数量为奇数,直接返回-1。

  3. 计算目标值:目标是将奇数位置和偶数位置的A数量都调整为总A数量的一半。

  4. 计算交换次数

    • 当奇数位置A不足时,从最近的偶数位置A移动到最近的可用奇数位置

    • 当奇数位置A过多时,从最近的奇数位置A移动到最近的可用偶数位置

  5. 交换次数计算:每次移动的交换次数等于当前位置与目标位置的差值。

复杂度分析

  • 时间复杂度:O(n),其中n是字符串长度。我们只需要遍历字符串一次统计A的位置,然后根据需要进行线性计算。

  • 空间复杂度:O(n),最坏情况下需要存储所有A的位置。

第四题:

题目描述

给定一个 n×n 的二维整数矩阵,你需要对这个矩阵的每一“圈层”的元素进行交错旋转,规则如下:

圈层的定义

  • 矩阵从最外层开始,向内逐层定义“圈层”。最外层的元素构成第一圈层,移除最外层后剩余矩阵的最外层元素构成第二圈层,以此类推。
  • 如果 n 为奇数,最中心的一个元素属于最内层的圈层,且旋转后其值不改变。

旋转方向

  • 最外层(第一圈层)的元素按照顺时针方向整体旋转 90 度。
  • 次外层(第二圈层)的元素按照逆时针方向整体旋转 90 度。
  • 再往内一层(第三圈层)的元素按照顺时针方向整体旋转 90 度。
  • 以此类推,圈层的旋转方向在顺时针和逆时针之间交替进行。

旋转范围

  • 每一圈层的旋转仅限于该圈层内的元素。

【原题有 n=4,6 的解释配图】

输入格式

第一行输入一个正整数 n(2≤n≤100),表示矩阵的行数和列数;

接下来 n 行,每行输入 n 个整数(−1000≤ 整数 ≤1000),整数之间以一个空格隔开。

输出格式

输出 n 行,每行 n 个整数,整数之间以一个空格隔开,表示经过圈层交错旋转 90 度变换后的矩阵。

输入输出样例

输入 #1复制

4
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16

输出 #1复制

13 9 5 1
14 7 11 2
15 6 10 3
16 12 8 4

题目分析

这道题目要求我们对矩阵的每一圈层进行交替方向的90度旋转。最外层顺时针旋转,次外层逆时针旋转,第三层顺时针旋转,以此类推。

关键点

  1. 圈层识别:需要正确识别矩阵的每一圈层

  2. 旋转方向交替:奇数次圈层顺时针旋转,偶数次圈层逆时针旋转

  3. 原地旋转:需要在原矩阵上进行旋转操作

解题思路

  1. 分层处理:从外到内逐层处理矩阵

  2. 确定旋转方向:根据层数决定顺时针或逆时针旋转

  3. 旋转实现

    • 顺时针旋转:将圈层分为上、右、下、左四边,依次交换

    • 逆时针旋转:将圈层分为上、左、下、右四边,依次交换

  4. 边界处理:对于奇数阶矩阵的中心元素不做处理

代码实现

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

// 顺时针旋转一层
void rotateClockwise(vector<vector<int>>& matrix, int layer) {
    int n = matrix.size();
    for (int i = 0; i < n - 1 - 2 * layer; i++) {
        // 保存上边
        int temp = matrix[layer][layer + i];
        // 左边到上边
        matrix[layer][layer + i] = matrix[n - 1 - layer - i][layer];
        // 下边到左边
        matrix[n - 1 - layer - i][layer] = matrix[n - 1 - layer][n - 1 - layer - i];
        // 右边到下边
        matrix[n - 1 - layer][n - 1 - layer - i] = matrix[layer + i][n - 1 - layer];
        // 上边到右边
        matrix[layer + i][n - 1 - layer] = temp;
    }
}

// 逆时针旋转一层
void rotateCounterClockwise(vector<vector<int>>& matrix, int layer) {
    int n = matrix.size();
    for (int i = 0; i < n - 1 - 2 * layer; i++) {
        // 保存上边
        int temp = matrix[layer][layer + i];
        // 右边到上边
        matrix[layer][layer + i] = matrix[layer + i][n - 1 - layer];
        // 下边到右边
        matrix[layer + i][n - 1 - layer] = matrix[n - 1 - layer][n - 1 - layer - i];
        // 左边到下边
        matrix[n - 1 - layer][n - 1 - layer - i] = matrix[n - 1 - layer - i][layer];
        // 上边到左边
        matrix[n - 1 - layer - i][layer] = temp;
    }
}

int main() {
    int n;
    cin >> n;
    vector<vector<int>> matrix(n, vector<int>(n));
    
    // 输入矩阵
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cin >> matrix[i][j];
        }
    }
    
    // 分层旋转
    for (int layer = 0; layer < n / 2; layer++) {
        if (layer % 2 == 0) {
            rotateClockwise(matrix, layer); // 偶数层顺时针
        } else {
            rotateCounterClockwise(matrix, layer); // 奇数层逆时针
        }
    }
    
    // 输出结果
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            cout << matrix[i][j];
            if (j != n - 1) cout << " ";
        }
        cout << endl;
    }
    
    return 0;
}

代码解释

  1. 旋转函数

    • rotateClockwise实现顺时针旋转一层

    • rotateCounterClockwise实现逆时针旋转一层

  2. 主流程

    • 读取输入矩阵

    • 从外到内逐层旋转,交替方向

    • 输出旋转后的矩阵

  3. 边界处理

    • 对于奇数n,中心元素自动保持不变

    • 旋转操作仅影响当前圈层元素

复杂度分析

  • 时间复杂度:O(n²),每个元素被访问常数次

  • 空间复杂度:O(1),原地旋转,仅使用常数额外空间

第五题:

题目描述

Jerry 和 Tom 正在进行一局游戏。他们准备了 n 个盒子,编号为 1 到 n,其中 i 号盒子装有 ai​ 枚硬币。他们将这 n 个盒子围成一圈。游戏规则如下:

  1. Jerry 和 Tom 轮流从某一个盒子中取走至少一枚硬币,Jerry 先手从 1 号盒子开始取;
  2. 如果前一个玩家取的是 i 号盒子中的硬币,那么当前玩家必须从 i+1 号盒子中取硬币。特别地,如果前一个玩家取的是 n 号盒子中的硬币,那么当前玩家必须从 1 号盒子中取硬币。
  3. 如果轮到某位玩家时对应盒子中没有硬币,则该玩家失败。

假设 Jerry 和 Tom 都采取最优策略,请问谁会赢?

输入格式

本题每个测试点包含多组测试数据,格式如下:

第一行输入一个整数 T(1≤T≤100),表示数据组数;

  • 对于每组测试数据,第一行输入一个整数 n(1≤n≤1000),表示盒子的数量;
  • 第二行输入 n 个整数 ai​(1≤ai​≤109),分别表示 1 号到 n 号盒子中的硬币数量,整数之间以一个空格隔开。

输出格式

输出 T 行,每行输出一个字符串,对于第 i 组测试数据,如果 Jerry 能赢,则输出 Jerry,否则输出 Tom。

输入输出样例

输入 #1复制

2
1
10
2
30 50

输出 #1复制

Jerry
Tom

接下来是全网第一篇AC题解:

题目分析

Jerry和Tom在玩一个环形取硬币游戏,规则如下:

  • n个盒子排成环,每个盒子有a[i]枚硬币

  • 玩家轮流取硬币,Jerry先手

  • 每次必须从前一个玩家取的盒子的下一个盒子取

  • 无法取硬币的玩家输

解题思路

通过分析游戏规则和博弈论原理,我们发现:

  1. 奇数个盒子(n为奇数):Jerry总能通过对称策略获胜

  2. 偶数个盒子(n为偶数):胜负取决于最小值的位置

    • 最小值在奇数位置:Tom胜

    • 最小值在偶数位置:Jerry胜

最优解法代码

#include <iostream>
using namespace std;

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int t, n;
    cin >> t;
    while (t--) {
        cin >> n;
        int minn = 1e9 + 1, pos = 0, a;
        
        // 找到最小值及其位置
        for (int i = 1; i <= n; ++i) {
            cin >> a;
            if (a < minn) {
                minn = a;
                pos = i;
            }
        }
        
        // 判断胜负
        if (n % 2 == 1) {
            cout << "Jerry\n";  // 奇数盒子Jerry必胜
        } else {
            // 偶数盒子取决于最小值位置
            cout << (pos % 2 == 1 ? "Tom\n" : "Jerry\n");
        }
    }
    return 0;
}

代码解释

  1. 输入处理

    • 使用快速输入输出优化

    • 读取测试用例数t

  2. 核心逻辑

    • 遍历所有盒子,找到最小值及其位置

    • 奇数n直接判定Jerry胜

    • 偶数n根据最小值位置的奇偶性判定胜负

  3. 输出结果

    • 直接输出当前测试用例的胜者

复杂度分析

  • 时间复杂度:O(T×n),每组数据需要线性扫描

  • 空间复杂度:O(1),仅使用常数空间

第六题:

题目描述

魔术师大卫将 n 张红色扑克牌和 n 张蓝色扑克牌混合在一起并打乱洗牌后,整齐叠放在桌子上。然后大卫请现场嘉宾从这叠牌最上面的扑克牌开始拿,连续拿取任意数量的牌组成一沓(至少拿 1 张,最多拿 2n 张)。接下来是见证奇迹的时刻,无论嘉宾拿多少张扑克牌,所拿取的这沓牌中红色扑克牌的数量都不少于蓝色扑克牌的数量。

给定红色扑克牌和蓝色扑克牌的张数 n,请帮魔术师计算出能实现上述魔术效果的扑克牌从上到下的排列方式共有多少种。

输入格式

输入一个整数 n(1≤n≤100),表示红色扑克牌和蓝色扑克牌各自的数量。

输出格式

输出一个整数,表示满足题目要求的排列方式有多少种。

输入输出样例

输入 #1复制

3

输出 #1复制

5

说明/提示

对于 3 红 3 蓝的牌,有以下 5 种排列方式满足条件(用 R 表示红牌,B 表示蓝牌):

  1. R R B R B B
  2. R B R B R B
  3. R B R R B B
  4. R R R B B B
  5. R R B B R B

【备注:原题为配图解释,由于没有高清图片,洛谷只提供书面文字说明】

这题纯卡特兰数,代码(不AC):

#include <iostream>
using namespace std;

long long combination(int n, int k) {
    if (k > n - k) k = n - k;
    long long res = 1;
    for (int i = 0; i < k; ++i) {
        res *= (n - i);
        res /= (i + 1);
    }
    return res;
}

long long catalanNumber(int n) {
    return combination(2 * n, n) / (n + 1);
}

int main() {
    int n;
    cin >> n;
    cout << catalanNumber(n) << endl;
    return 0;
}

本蒟蒻已尽力写完整篇文章,觉得不错的话,就点个关注叭!

### 第十一届蓝桥杯 C++ B 题解与经验总结 #### 基础知识点概述 第十一届蓝桥杯 C++ B考察的知识点较为广泛,涵盖了简单的数学计算、字符串处理、模拟算法以及动态规划等内容。对于参者而言,熟悉这些基础知识是非常重要的[^2]。 #### 解析具体目 以下是针对部分典型目的解析: 1. **填空** - 这类目通常涉及基本的数学运算或者逻辑推理。例如,在某道填空中可能需要考生快速判断某个数值范围内的素数数量。这类问可以通过埃拉托色尼筛法高效解决。 2. **简单模拟** - 模拟问是比中常见的类型之一,它要求选手按照给定规则逐步操作数据结构来得出最终结果。比如一道关于队列进出顺序的问可以借助 STL 中 queue 容器轻松实现。 3. **广度优先搜索 (BFS) 和深度优先搜索 (DFS)** - 对于一些路径寻找或连通性检测的问,则需要用到 BFS 或 DFS 技术。这两种方法均能有效探索图中的节点关系,并找到目标位置或是验证是否存在特定连接情况。 4. **动态规划 (DP) 初步应用** - 动态规划作为优化求解复杂问的强大工具,在某些情况下也被引入到此类竞当中。虽然当前阶段很多学生还未完全掌握 DP 的精髓——即如何设计合适的状态转移方程,但对于相对直观的小规模实例还是能够尝试运用递推思想去解答。 ```cpp // 示例代码:使用BFS解决问 #include <bits/stdc++.h> using namespace std; int main(){ int n; cin >> n; // 输入矩阵大小n*n vector<vector<int>> grid(n, vector<int>(n)); for(auto &row : grid){ for(auto &cell : row){ cin >> cell; // 初始化网格 } } bool visited[n][n]; memset(visited, false, sizeof(visited)); queue<pair<int,int>> q; q.push({0, 0}); visited[0][0]=true; while(!q.empty()){ auto current=q.front(); q.pop(); // 处理当前位置... // 将未访问过的邻居加入队列 if(current.first+1<n && !visited[current.first+1][current.second]){ visited[current.first+1][current.second]=true; q.push({current.first+1,current.second}); } // 类似地检查其他方向... } } ``` #### 参加比的经验分享 - **时间管理**: 在有限时间内合理分配每道的时间至关重要。建议先浏览全部试,从最容易得分的部分入手。 - **调试技巧**: 编写清晰简洁的程序有助于减少错误率;同时利用样例输入反复测试自己的解决方案直至确认无误再提交。 - **心理素质培养**: 保持冷静头脑面对突发状况也是成功的关键因素之一。即使遇到难也不要慌张,继续专注剩余可做之。 ---
评论 8
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值