第十六届蓝桥杯软件赛 C 组省赛 C++ 题解

大家好,今天是 2025 年 9 月 11 日,我来给大家写一篇关于第十六届蓝桥杯软件赛 C 组省赛的C++ 题解,希望对大家有所帮助!!!

创作不易,别忘了一键三连

题目一:数位倍数

题目链接:数位倍数

【题目描述】

【算法原理】

签到题、枚举、数位拆分

只需要暴力枚举 1 到 202504 之间的所有整数,对于每一个整数,拆分它的每一位求和之后看看是不是 5 的倍数就可以了。

至于如何拆分一个整数的每一位,相信大家已经掌握的非常熟练了,直接来看代码。

【代码实现】

#include <iostream>using namespace std;bool check(int x)
{int sum = 0; // 统计每一个数的数位和while(x){sum += x % 10;x /= 10;}return sum % 5 == 0;
}int main()
{int cnt = 0;for(int i = 1; i <= 202504; i++)if(check(i))cnt++;cout << cnt << endl; return 0;
} 

题目二:2025

题目链接:2025

【题目描述】

【算法原理】

签到题、枚举、数位拆分

和题目一类似,只需要暴力枚举 1 到 20250412 之间的所有整数,对于每一个整数,拆分它的每一位并统计,之后看看是不是含有至少 1 个 0,2 个 2,1 个 5 就可以了。

至于如何拆分一个整数的每一位,相信大家已经掌握的非常熟练了,直接来看代码。

【代码实现】

#include <iostream>
#include <cstring>using namespace std;int cnt[10]; // cnt[i] 表示 i 这个数字出现了多少次bool check(int x)
{memset(cnt, 0, sizeof cnt);while(x){cnt[x % 10]++;x /= 10;}if(cnt[0] < 1 || cnt[2] < 2 || cnt[5] < 1) return false; return true;
}int main()
{int c = 0;for(int i = 1; i <= 20250412; i++)if(check(i))c++;cout << c << endl; return 0;
}

题目三:2025图形

题目链接:2025图形

【题目描述】

【算法原理】

签到题、模拟、取模运算

找规律 + 周期问题

这道题数据范围很小,我们完全可以首先构造出一个含有 200 个 “2025” 的字符串,然后针对每一行从不同的位置开始输出 w 个字符就可以了。(代码可以自己尝试实现)

但是,这样玩的话就没有什么意思了。我们能不能只存一个 “2025” 呢?

我们写几行找一找规律:

遇到周期问题,我们就要首先想到取模操作。

不难发现,这道题输出位置的值的下标就是横坐标的值和纵坐标的值之和再模四。

因此,这道题的规律我们就找到了,直接来看代码:

【代码实现】

#include <iostream>using namespace std;int a[4] = {2, 0, 2, 5};int main()
{int h, w; cin >> h >> w;for(int i = 0; i < h; i++){for(int j = 0; j < w; j++){cout << a[(i + j) % 4];} cout << endl;}return 0;
} 

题目四:最短距离

题目链接:最短距离

【题目描述】

【算法原理】

贪心

这道题目一定不要一直拘泥于题目中的那一幅图当中,我们抛开坐标系不谈,其实这道题目就是让两个数组中的值一一对应,使得每一组差的绝对值之和最小:

(我当时就盯着题目中的那幅图在坐标系中想了很长时间)

我们很容易想到一个贪心策略,就是将两个数组排序之后,然后按照从小到大的顺序一一对应就可以了。

大家如果之前接触过这一类贪心问题的话,贪心策略是很好想出来的。但是如果之前没接触过这样的问题,就把这个贪心策略当成一个经验积累下来,以后再遇到这样的问题直接朝这方面想就可以了~~

(想出贪心策略之后,自己构造几组测试用例,如果没有明显的错误的话,直接写代码就 OK 了)(由于这里是赛后题解,我接下来会给出详细证明)。

贪心策略的正确性证明:反证法(有兴趣的可以看一看下面)

我们假设不是按照下标一位一位对应,只需要证明这样反着来绝对没有正着来更优就可以了。

假设 i < j,a[i] <= a[j],b[i] <= b[j]:

如果正着来的话,我们会让 a[i] 和 b[i] 对应,a[j] 和 b[j] 对应。

如果反着来的话,我们会让 a[i] 和 b[j] 对应,a[j] 和 b[i] 对应。

接下来只需要证明在所有的情况下反着来都没有正着来更优就可以了。

我们根据 a[i] a[j] b[i] b[j] 的位置(大小关系)分情况讨论:

其余情况都类似,就不一一列举了!!!

【代码实现】

#include <iostream>
#include <algorithm>
#include <cmath>using namespace std;typedef long long LL;
const int N = 5e4 + 10;int n;
LL a[N], b[N];int main()
{cin >> n;for(int i = 1; i <= n; i++) cin >> a[i];for(int i = 1; i <= n; i++) cin >> b[i];sort(a + 1, a + 1 + n);sort(b + 1, b + 1 + n);LL ret = 0;for(int i = 1; i <= n; i++)	ret += abs(a[i] - b[i]);cout << ret << endl;return 0;
}

题目五:冷热数据队列

题目链接:冷热数据队列

【题目描述】

【算法原理】

数据结构 + 模拟

1. 查找 :哈希表、红黑树;

2. 头插:链表,双端队列;

3. 任意位置删除:双向链表;

4. 尾删:链表,双端队列;

由于本题我们需要执行查找操作,因此我们需要哈希表(或红黑树)这一数据结构。

我们还需要执行任意位置删除和头插操作,因此我们需要双向链表。(STL 中的 List 就行)

执行查找操作要用到的哈希表要能够配合双向链表的删除操作,因此我们这样创建哈希表:

至于 STL 中的 list,我们之前很少使用,这里给大家一些常见的接口:

接下来就是根据题目要求进行模拟的过程了,废话不多说,直接来看代码。 

【代码实现】

#include <iostream>
#include <list>
#include <unordered_map>using namespace std;int n1, n2, m;
list<int> q1, q2;
unordered_map<int, list<int>::iterator> mp1, mp2;int main()
{cin >> n1 >> n2 >> m;while(m--){int x; cin >> x;if(mp1.count(x)){// ɾq1.erase(mp1[x]);mp1.erase(x);// ƶ q1.push_front(x);mp1[x] = q1.begin();}else if(mp2.count(x)){// ɾq2.erase(mp2[x]);mp2.erase(x);// ƶ q1.push_front(x);mp1[x] = q1.begin();}else{q2.push_front(x);mp2[x] = q2.begin();}if(q1.size() > n1){int x = *q1.rbegin();q1.pop_back();mp1.erase(x);q2.push_front(x);mp2[x] = q2.begin();}if(q2.size() > n2){int x = *q2.rbegin();q2.pop_back();mp2.erase(x);}}for(auto x : q1) cout << x << " ";cout << endl;for(auto x : q2) cout << x << " ";cout << endl; return 0;
} 

题目六:倒水

题目链接:倒水

【题目描述】

【算法原理】

二分答案

这道题目有明显的二分题眼,要求的是最小值最大是多少。

分析二段性:

我们假设最终答案 ret 表示最小值的最大情况,我们发现如果再大于 ret 的话,是没有办法做到的,如果小于 ret 的话,我们是可以做到的。因此本题具有明显的二段性,我们就可以尝试使用二分答案来进行解决

接下来思考如何实现 check 函数?

我们传入一个值 mid,check 函数的功能是判断能否通过倒水使得所有瓶子中的最小值大于等于 x,如果能,说明 mid 落在了左区间。如果不能说明 mid 落到了右区间。

我们只需要从前往后遍历一遍数组,只要该位置的水量大于等于 x,我们就把多余的水往后倒,如果遍历到某一位置发现水量小于 x,就返回 false,如果全部大于等于 x,就返回 true;

我们直接来看代码:

【代码实现】

#include <iostream>
#include <cstring>using namespace std;typedef long long LL;
const int N = 1e5 + 10;LL n, k; 
LL a[N];
LL b[N];bool check(LL x)
{memcpy(b, a, sizeof a);for(int i = 1; i <= n; i++){if(b[i] < x) return false;b[i] -= x;if(i + k <= n) b[i + k] += b[i];} return true;
}int main()
{cin >> n >> k;for(int i = 1; i <= n; i++) cin >> a[i];int l = 0, r = 1e5;while(l < r){int mid = (l + r + 1) >> 1;if(check(mid)) l = mid;else r = mid - 1;}cout << l << endl;return 0;
}

题目七:拼好数

题目链接:拼好数

【题目描述】

【算法原理】

贪心 + 分类讨论

这道题首先大家都可以想到是要统计每一个数中 6 的个数,然后再考虑拼接的问题。

我们预处理出一个 cnt 数组,其中 cnt[i] 表示:出现 6 的次数为 i 时,一共有多少个数。

比如,以第二个测试用例为例,cnt[6] = 1,cnt[3] = 3,cnt[1] = 3;

贪心策略:

1. 如果一个数 6 的出现次数大于等于 6,直接让 ret + 1 即可,这个数可以单独成为一个小组。

2. 如果能用 1 去凑,就尽量先使用 1 去凑;因为1 不能单独凑成 6,只能和别的数配合使用。

    能用 1 就先用 1,这样就可以把其余更有用的数保留下来,去凑更多的可能性。

3. 在第二点的基础上,如果能用更少的数凑成,就不用更多的数。

4. 在前面几点的基础上,优先用更容易凑出 6 的数去拼凑。 

直观感受一下,这个贪心策略肯定是正确的~~~

那我们就确定了各种拼凑方式的优先级:

然后我们就可以去写代码了,废话不多说,直接来看代码:

【代码实现】

#include <iostream>using namespace std;const int N = 10;int n;
int cnt[N];// 统计 6 出现的次数 
int calc(int x)
{int c = 0;while(x){if(x % 10 == 6) c++;x /= 10;}return c;
}int main()
{cin >> n;int ret = 0;for(int i = 1; i <= n; i++){int x; cin >> x;int t = calc(x);if(t >= 6) ret++;else cnt[t]++;}// 分类讨论if(cnt[5]){// 5 + 1  5 + 2  5 + 3  5 + 4 for(int i = 1; i <= 4 && cnt[5]; i++){// cnt[i] + cnt[5]if(cnt[5] <= cnt[i]){ret += cnt[5];cnt[i] -= cnt[5];cnt[5] = 0;} else{ret += cnt[i];cnt[5] -= cnt[i];cnt[i] = 0;}} ret += cnt[5] / 2;} if(cnt[4]){// 4 + 1 + 1if(cnt[4] * 2 <= cnt[1]){ret += cnt[4];cnt[1] -= cnt[4] * 2;cnt[4] = 0; } else{ret += cnt[1] / 2;cnt[4] -= cnt[1] / 2;cnt[1] %= 2;}// 4 + 2  4 + 3for(int i = 2; i <= 3 && cnt[4]; i++){// cnt[i] + cnt[4]if(cnt[4] < cnt[i]){ret += cnt[4];cnt[i] -= cnt[4];cnt[4] = 0;} else{ret += cnt[i];cnt[4] -= cnt[i];cnt[i] = 0;}} // 4 + 4ret += cnt[4] / 2;} if(cnt[3]){// 3 + 1 + 2if(cnt[1] && cnt[2]){int t = min(min(cnt[1], cnt[2]), cnt[3]);ret += t;cnt[1] -= t;cnt[2] -= t;cnt[3] -= t;}// 3 + 3ret += cnt[3] / 2;cnt[3] %= 2;// 3 + 2 + 2 -> 2 + 2 + 2 cnt[2] += cnt[3]; }ret += cnt[2] / 3;cout << ret << endl;return 0;
} 

题目八:登山

题目链接:登山

【题目描述】

【算法原理】

本场比赛的压轴题目、逆序对、图论、并查集、单调栈

首先我们要模拟一下输入输出样例,弄明白题目让我们做什么。

这道题目从起点的行走方式如下:

我们先不要考虑二维,可以发现:无论横着看还是竖着看,只要是构成逆序对的话,就有双向边。

那么这道题目就可以转化成一个图论问题

由于二维坐标不好处理,我们先把二维坐标转化成一维坐标

根据逆序对建图之后,我们只需要统计每一个连通块(并查集)的最大值,再把所有的点遍历一遍,判断它是在哪一个连通块,直接累加上这个最大值就可以了。

接下来考虑下一个问题:如何把这个图给建出来呢???

肯定不能直接把所有的逆序对都连上双向边,因为时间和空间都不允许。(共 nmm + mnn 条边)

但是我们发现,图是没有必要完全建出来的,我们仅需搞定并查集能够找到连通块中的最大值就可以了。

因此,我们这样来处理这个问题:(当成经验积累下来)

我们从前往后遍历数组,如果该元素比前一个位置小,就一直往前合并并查集,顺便删除合并过的元素,直到该元素比前面的元素大。再把该元素存储起来。

类似单调栈的过程,我们用栈来模拟这个过程。

我们直接来看代码:

【代码实现】

#include <iostream>using namespace std;const int N = 1e6 + 10;int n, m;
int a[N];
int fa[N]; // 并查集
int st[N], top; // 栈// 二维转一维
int get_id(int i, int j)
{return i * m + j;
} int find(int x)
{return fa[x] == x ? x : fa[x] = find(fa[x]);
}void merge(int x, int y)
{x = find(x), y = find(y);if(x == y) return;// 小的合并到大的 if(a[x] >= a[y]) fa[y] = x;else fa[x] = y;
}int main() 
{cin >> n >> m;for(int i = 1; i < n * m; i++) fa[i] = i;for(int i = 0; i < n; i++)for(int j = 0; j < m; j++)cin >> a[get_id(i, j)];// 建图for(int i = 0; i < n; i++){top = 0;for(int j = 0; j < m; j++){int t = top, id = get_id(i, j);while(top && a[st[top]] > a[id]){merge(st[top], id);top--;}if(t == top) st[++top] = id;else st[++top] = st[t];}} for(int j = 0; j < m; j++){top = 0;for(int i = 0; i < n; i++){int t = top, id = get_id(i, j);while(top && a[st[top]] > a[id]){merge(st[top], id);top--;}if(t == top) st[++top] = id;else st[++top] = st[t];}} double ret = 0;for(int i = 0; i < n * m; i++) ret += a[find(i)];printf("%.6lf\n", ret / (n * m));return 0;
}

好了,本期的内容就到这里了。期待我们下次见面。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/pingmian/96345.shtml
繁体地址,请注明出处:http://hk.pswp.cn/pingmian/96345.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

项目帮助文档的实现

项目帮助文档的实现 代码如下&#xff1a; #ifndef __M_HELPER_H__ #define __M_HELPER_H__ #include <iostream> #include <fstream> #include <string> #include <vector> #include <sqlite3.h> #include <random> #include <sstream…

python逆向-逆向pyinstaller打包的exe程序反编译获取源代码

python逆向-逆向pyinstaller打包的exe程序反编译获取源代码 Pyinstaller pyinstaller 是一个用于将 Python 程序打包成独立可执行文件的工具&#xff0c;能够在没有 Python 解释器的情况下运行。 Python 脚本转换为 Windows、macOS 和 Linux 操作系统上的可执行文件。 把Python…

【SQL】-- sql having 和 where 的 区别

HAVING 和 WHERE 都是用来筛选数据的&#xff0c;但它们的应用场景有所不同。WHERE&#xff1a;用于筛选行数据&#xff0c;通常在 FROM 子句之后执行。它在分组操作 (GROUP BY) 之前应用&#xff0c;用来筛选出符合条件的记录。示例&#xff1a;SELECT name, age FROM employe…

MySQL,SQL Server,PostgreSQL三种数据库各自的优缺点,分别适用哪些场景

MySQL的优缺点及适用场景优点开源免费&#xff0c;社区版可商用&#xff0c;成本低。轻量级&#xff0c;安装配置简单&#xff0c;适合中小型项目。读写性能优异&#xff0c;尤其在OLTP&#xff08;在线事务处理&#xff09;场景下表现突出。支持主从复制、分片等扩展方案&…

Java 类加载机制双亲委派与自定义类加载器

我们来深入解析 Java 类加载机制。这是理解 Java 应用如何运行、如何实现插件化、以及解决一些依赖冲突问题的关键。一、核心概念&#xff1a;类加载过程一个类型&#xff08;包括类和接口&#xff09;从被加载到虚拟机内存开始&#xff0c;到卸载出内存为止&#xff0c;它的整…

Kaggle项目实践——Titanic: Machine Learning from Disaster

泰坦尼克号沉船事件是机器学习领域最经典的入门项目之一。Kaggle 上的 Titanic: Machine Learning from Disaster 竞赛&#xff0c;被无数人称为“机器学习的 Hello World”。 一、数据导入与清洗&#xff1a;让数据从 “杂乱” 变 “干净” 机器学习模型就像 “挑食的孩子”…

Qt C++ 复杂界面处理:巧用覆盖层突破复杂界面处理难题​之二

接上一篇&#xff0c;继续探索“覆盖层”的使用方法。 五、覆盖层进阶交互&#xff1a;从 “能绘制” 到 “好操作”​ 基础的绘制功能只能满足 “看得见” 的需求&#xff0c;实际开发中还需要 “能操作”—— 比如选中线条修改颜色、按 Delete 键删除线条、鼠标 hover 时高亮…

神经网络构成框架-理论学习

一、神经网络的基本组成与分类 1.1 神经网络的核心组成部分 神经网络是现代人工智能的基石&#xff0c;其设计灵感来源于生物神经系统的信息处理方式。作为工程师&#xff0c;了解神经网络的基本组成部分对于构建和优化模型至关重要。一个典型的神经网络主要由以下几个关键部分…

从0开始开发app(AI助手版)-架构及环境搭建

架构选择 前端React Native 后端Firebase 原因 环境准备 安装node 安装JDK 命令行工具&#xff1a;Node.js command prompt命令行查询Javav版本&#xff1a;javac -version使用nrm工具切换淘宝源&#xff1a;npx nrm use taobao安装yarn&#xff0c;替代npm下载工具&#x…

【性能测试】Jmeter工具快速上手-搭建压力测试脚本

&#x1f525;个人主页&#xff1a; 中草药 &#x1f525;专栏&#xff1a;【Java】登神长阶 史诗般的Java成神之路 概念 性能测试是软件测试的重要分支&#xff0c;核心目标是通过模拟真实业务场景和负载压力&#xff0c;评估系统在不同条件下的性能表现&#xff0c;发现系统性…

oracle里的int类型

oracle里的int类型 在 ANSI SQL 标准 中&#xff0c;INTEGER 和 SMALLINT 是定义好的精确数值类型&#xff0c;但它们的 “长度”或“大小”并不是通过 (N) 括号来指定的&#xff08;如 INT(4)&#xff09;&#xff0c;这一点与 MySQL 等数据库的非标准扩展完全不同。 SMALLI…

前端学习之后端java小白(二)-sql约束/建表

一、约束SQL约束&#xff08;Constraints&#xff09;是用于限制表中数据的规则&#xff0c;确保数据的完整性和准确性。以下是主要的SQL约束类型&#xff1a; 主要约束类型&#xff1a; 1. NOT NULL 约束: 确保列不能包含空值 CREATE TABLE users (id INT NOT NULL,name VARC…

OpenCV:图像金字塔

文章目录一、什么是图像金字塔&#xff1f;二、图像金字塔的核心操作&#xff1a;采样与逆采样1. 向下采样&#xff08;pyrDown&#xff09;&#xff1a;从高分辨率到低分辨率步骤1&#xff1a;高斯滤波步骤2&#xff1a;删除偶数行与偶数列OpenCV实战代码效果特点2. 向上采样&…

LVS与Keepalived详解(一)负载均衡集群介绍

文章目录前言一、什么是LVS&#xff1f;二、四层&#xff08;L4&#xff09;负载均衡的最佳解决方案是什么&#xff1f;2.1解决方案分类与对比&#xff08;负载均衡的三种方式介绍&#xff09;2.1.1 硬件负载均衡 (Hardware Load Balancer)2.1.2 软件负载均衡 (Software Load B…

消息队列-kafka完结

基本概念和操作 基本概念 简单概念:::color4 Broker&#xff1a;如果将kafka比喻成数据仓库网络&#xff0c;那么Broker就是网络中的仓库节点&#xff0c;比如快递站&#xff0c;在该节点内可以独立运行&#xff0c;并且多个Broker可以连接起来&#xff0c;构建kafka集群Topic&…

Chromium 138 编译指南 Windows篇:环境变量配置与构建优化(三)

引言配置&#xff0c;往往决定成败。在软件开发的世界里&#xff0c;环境变量就像是一位无声的指挥家&#xff0c;默默地协调着各个组件的协同工作。对于Chromium 138这样一个拥有数千万行代码的超大型项目而言&#xff0c;正确的环境变量配置更是编译成功的关键所在。也许您曾…

LabVIEW加载 STL 模型至 3D 场景 源码见附件

LabVIEW 中 STL 模型的导入与 3D 场景显示&#xff0c;基于示例代码逻辑&#xff0c;结合格式兼容性、功能实现步骤及多样化显示方式&#xff0c;适用于三维可视化温控、机械零件模拟等场景。 1示例代码 NI 社区案例 “Add an STL file to 3D scene using LabVIEW” 提供了经…

硅基计划3.0 Map类Set类

文章目录一、二叉搜索树&#xff08;排序树&#xff09;1. 概念初识2. 模拟实现1. 创建搜索树节点2. 查找指定元素是否存在3. 插入4. 删除二、Map类1. put——设置单词以及其频次2. get——获取单词频次3. getOrDefault——获取单词频次或返回默认值4. remove——删除单词频次信…

LeetCode 刷题【73. 矩阵置零】

73. 矩阵置零 自己做 解&#xff1a;标记消除 class Solution { public:void setZeroes(vector<vector<int>>& matrix) {vector<bool> x(matrix.size(), false); //要置0的行vector<bool> y(matrix[0].size(), false); //…

Unity学习----【进阶】TextMeshPro学习(一)--基础知识点

来源于唐老狮的视频教学&#xff0c;仅作记录和感悟记录&#xff0c;方便日后复习或者查找 一.导入TextMeshPro 对于新创建的工程&#xff0c;可以直接在这里导入TMP必要的资源&#xff08;上面&#xff09;&#xff0c;以及TMP的实例和扩展&#xff08;下面&#xff09; 导入之…