IT评测·应用市场-qidao123.com

标题: 第十五届蓝桥杯C/C++ C 组全部题目详细题解 [打印本页]

作者: tsx81429    时间: 2025-3-14 18:23
标题: 第十五届蓝桥杯C/C++ C 组全部题目详细题解
本文为第十五届蓝桥杯C/C++ C 组全部题目标详细题解,题目均来自于蓝桥杯官网,真题链接:
蓝桥杯真题卷 - 蓝桥云课
觉的有资助或者写的不错可以点个赞,如果我题解写的有问题也欢迎评论指出,欢迎友爱讨论

目录

题一:拼正方形 - 简单数学
题目大意:
解题思路:
代码(C++):
题二:劲舞团 - 模拟
题目大意:
解题思路:
代码(C++):
题三:数字诗意 - 找规律,简单数学证实
题目大意:
解题思路:
代码(C++):
题四:封闭图形个数 - 自定义排序 + 简单模拟
题目大意:
解题思路:
代码(C++):
题五: 回文数组 - 贪心
题目大意:
解题思路:
代码(C++):
题六:商品库存管理 - 差分
题目大意:
解题思路:
代码(C++):
题七:挖矿 - 排序 + 二分查找 / 前缀和
题目大意:
解题思路:
方法一: 枚举一边选的个数 + 排序 + 二分查找
代码(C++):
方法二:枚举移动距离 - 前缀和
代码(C++):
题八:回笔墨符串 - 双指针
题目大意:
解题思路:
代码(C++):


题一:拼正方形 - 简单数学

0拼正方形 - 蓝桥云课
题目大意:

给你一些2 * 2的正方形和一些1 * 1的正方形
2 * 2的正方形个数为7385137888721,1 * 1的正方形个数为10470245
请问这些正方形能拼出的最大正方形边长为多少?
解题思路:

可以看出2 * 2的正方形个数是远大于1 * 1的正方形个数的。
那么我们可以这么做,先用2*2的正方形全部用来拼一个正方形。
可以拼的数目为7385137888721 ^(1/2)的整数部门,我们可以用盘算器算出来为2717561,也就是用掉2717561个2 * 2的正方形。
这个正方形的边长为2717561 * 2 = 5435122。需要用掉5435122 * 2 + 1= 10870245个1*1的正方形才气使得这个正方形的边长加1。
这个数目是大于已有的1*1的正方形个数,所以1 * 1的正方形是用不上的,最后的边长为5435122
代码(C++):

  1. #include <bits/stdc++.h>
  2. int main() {
  3.     std::cout << 5435122;
  4. }
复制代码
题二:劲舞团 - 模拟

0劲舞团 - 蓝桥云课
题目大意:

给你一些敲击记录,每一条敲击记录包罗三个数据,分别是正确的字符,敲出的字符,毫秒时间戳。(此中时间戳包管从小到大排序)
现在定义一个K最大连击:在连续的K次敲击中,都禁绝有错误,并且每一个相邻的两次敲击时间小于等于1s。
请你找出这些敲击记录中K最大连击这个K的最大值
解题思路:

模拟题,可以直接看代码明白
我们用一个cur来判定当前的连击次数,last 存上一个时间
首先判定此时是否是正确答案,也就是t == s
如果是正确答案,我们就看上一个是否也是正确答案(我这里用last来判定), 来更新cur
更新完后把last设置成此时的time

如果不是正确答案,把last 变成-1

每次判定完后更新cur的最大值即可
代码(C++):

  1. #include <bits/stdc++.h>
  2. using i64 = long long;
  3. int main() {
  4.     char t, s;
  5.     i64 time, last;
  6.    
  7.     int ans = 0, cur;
  8.    
  9.     while (std::cin >> t >> s >> time) {
  10.         if (t == s) {
  11.             if (last == -1) {
  12.                 last = time;
  13.                 cur = 1;
  14.             } else {
  15.                 if (time - last <= 1000) {
  16.                     cur++;
  17.                 } else {
  18.                     cur = 1;
  19.                 }
  20.             }
  21.             last = time;
  22.         } else {
  23.             last = -1;
  24.         }
  25.         ans = std::max(ans, cur);
  26.     }
  27.     std::cout << ans;
  28. }
复制代码
把log.txt的数据输出进去算出的是9然后输出9即为正确答案
题三:数字诗意 - 找规律,简单数学证实

0数字诗意 - 蓝桥云课
题目大意:

定义一个数字:
可以表示成连续的(至少两个)正整数相加,那么这个数字就是有诗意的
例如:
3 = 1 + 2
5 = 2 + 3
6 = 1 + 2 + 3
7 = 3 + 4
....
现在给你一n个数字,你需要删除此中的一些数字(可以为0),使得剩下的数字全部是有诗意的
解题思路:

结论: 为2的若干幂次的数字没有诗意,1也没有诗意
直接列举可以猜出这个结论
严酷证实的话,主要就是从等差数列求和公式出发证实
题解区有详细证实,这里就不写了(
然后问题就变成了,怎么判定一个数字是否是2的幂次
可以发现,如果一个数字是2的幂次,那么它一定可以一直除以2,直到为1
我们可以一直判定这个数字是否是偶数,如果是偶数,那么就除以2,最后判定是不是1就行
时间复杂度为O(n * log n)
代码(C++):

  1. #include <bits/stdc++.h>
  2. using i64 = long long;
  3. bool check(i64 x) { //这里也要开long long
  4.     while (x > 0) {
  5.         if (x % 2 == 0) {
  6.             x /= 2;
  7.         } else {
  8.             break;
  9.         }
  10.     }
  11.     return x == 1;
  12. }
  13. int main() {
  14.     int n;
  15.     std::cin >> n;
  16.     int ans = 0;
  17.     for (int i = 0; i < n; i++) {
  18.         i64 x; //注意题目范围得开long long
  19.         std::cin >> x;
  20.         if (check(x)) {
  21.             ans++;
  22.         }
  23.     }
  24.    
  25.     std::cout << ans;
  26. }
复制代码
题四:封闭图形个数 - 自定义排序 + 简单模拟

0封闭图形个数 - 蓝桥云课
题目大意:

题目定义4, 6, 9, 0分别有一个封闭图形 , 8有两个封闭图形
现在给你一个数组,你需要对数组里面的元素进行排序,一个数字所含的封闭图形总数小的排在前面,如果封闭图形个数相同,那么数字本身小的在前面
解题思路:

我们先定义一个函数求出一个数字的封闭图形个数
然后用自定义排序函数,根据题目意思模拟就行
具体看代码
代码(C++):

  1. #include <bits/stdc++.h>
  2. int cal(int x) {
  3.     int res = 0;
  4.     while (x > 0) {
  5.         int cur = x % 10;
  6.         if (cur == 8) {
  7.             res += 2;
  8.         }
  9.         if (cur == 4 || cur == 6 || cur == 9 || cur == 0) {
  10.             res++;
  11.         }
  12.         x /= 10;
  13.     }
  14.     return res;
  15. }
  16. int main() {
  17.     int n;
  18.     std::cin >> n;
  19.     std::vector<int> a(n);
  20.     for (int i = 0; i < n; i++) {
  21.         std::cin >> a[i];
  22.     }
  23.     std::sort(a.begin(), a.end(), [&](int i, int j) {
  24.         if (cal(i) == cal(j)) {
  25.             return i < j;
  26.         }
  27.         return cal(i) < cal(j);
  28.     });
  29.     for (int i = 0; i < n; i++) {
  30.         std::cout << a[i] << " ";
  31.     }
  32.     std::cout << "\n";
  33. }
复制代码
题五: 回文数组 - 贪心

0回文数组 - 蓝桥云课
题目大意:

给你一个长度为n的数组,你需要让数组变成回文数组:
每次操作,你可以从以下两个操作中选择一个进行:
1.选择一个数字,让它加一或者减一
2.选择两个相邻的数字,同时让他们加一或者减一
现在请你输出把数组变成回文数组所需要的最小操作次数
解题思路:

关键点1:要使得数组为回文数组,我们只需要操作数组的左边边让其等于右半边即可
为了方便明白和盘算,我们可以建立一个长度为n / 2的数组b,此中b = a - a[n - i - 1]
也就是原来数组与对称的一边的元素的差值
然后现在就变成了:我们需要通过操作使得这个数组b的全部值为0
贪心的想,要使得操作次数最小,我们需要进行更多的操作2,也就是对b数组中”同号“且”相邻“的元素进行操作
我们可以这样模拟这个操作过程:(具体可以看代码明白)
遍历数组b,不断检查相邻的两个元素
如果同号,那么就让绝对值小的谁人为0,答案加上这个绝对值小的值,绝对值大的减去绝对值小的 (操作二)
如果不同号,那么就只把当前这个变成0即可 (操作一)
最后再遍历检查一遍,加上每个元素的绝对值 (也就是使用操作一)
代码(C++):

  1. #include <bits/stdc++.h>
  2. using i64 = long long;
  3. int main() {
  4.     int n;
  5.     std::cin >> n;
  6.     std::vector<int> a(n);
  7.     for (int i = 0; i < n; i++) {
  8.         std::cin >> a[i];
  9.     }
  10.     std::vector<i64> b(n / 2);
  11.     for (int i = 0; i < n / 2; i++) {
  12.         b[i] = a[i] - a[n - i - 1];
  13.     }
  14.     i64 ans = 0;
  15.     for (int i = 0; i < n / 2 - 1; i++) {
  16.         if (b[i] * b[i + 1] > 0) {
  17.             ans += std::min(abs(b[i]), abs(b[i + 1]));
  18.             if (abs(b[i]) < abs(b[i + 1])) {
  19.                 b[i + 1] -= b[i];
  20.                 b[i] = 0;
  21.             } else {
  22.                 b[i] -= b[i + 1];
  23.                 b[i + 1] = 0;
  24.             }
  25.         } else {
  26.             ans += abs(b[i]);
  27.             b[i] = 0;
  28.         }
  29.     }
  30.     for (int x : b) {
  31.         ans += abs(x);
  32.     }
  33.     std::cout << ans;
  34. }
复制代码
题六:商品库存管理 - 差分 + 前缀和

此题蓝桥官网的数据有问题,暴力O(n ^ m)也能过,这里讲差分写法
0商品库存管理 - 蓝桥云课
题目大意:

题目可以这么明白:
给你一个长度为n的数组,起初数组里面元素都为0, 再给你m个操作,每个操作为一个区间 [L, R]
表示把这个区间内全部的元素都加1
现在你需要做的是,对面m个操作中的每一个操作,如果不进行这个操作,那么最后数组中有多少个数字为0
解题思路:

差分的原理可以参考:
1094. 拼车 - 力扣(LeetCode)

关键点:我们先把全部的操作完成(可以用差分),得到终极的数组,然后,此中一个操作不做表示把一段区间全部-1,我们只需要统计每段区间1的个数即可
可以用前缀和头脑,快速的盘算一段区间的1的个数
代码(C++):

  1. #include <bits/stdc++.h>
  2. int main() {
  3.     int n, m;
  4.     std::cin >> n >> m;
  5.     std::vector<int> d(n + 1, 0); //差分数组,具体可以看链接的原理
  6.     std::vector<int> l(m), r(m);
  7.     for (int i = 0; i < m; i++) {
  8.         std::cin >> l[i] >> r[i];
  9.         l[i]--;
  10.         d[l[i]]++;
  11.         d[r[i]]--;
  12.     }
  13.     std::vector<int> a(n, 0); //所有操作完后的数组
  14.     a[0] = d[0];
  15.     int tot = (a[0] == 0); //统计所有操作完还为0的个数
  16.     for (int i = 1; i < n; i++) {
  17.         a[i] = a[i - 1] + d[i];//根据差分数组还原
  18.         if (a[i] == 0) {
  19.             tot++;
  20.         }
  21.     }
  22.     std::vector<int> pref(n + 1, 0); //前缀和数组
  23.     for (int i = 0; i < n; i++) {
  24.         pref[i + 1] = pref[i] + (a[i] == 1);
  25.     }
  26.     for (int i = 0; i < m; i++) {
  27.         std::cout << pref[r[i]] - pref[l[i]] + tot << "\n";
  28.     }
  29. }
复制代码

题七:挖矿 - 排序 + 二分查找 / 前缀和

0挖矿 - 蓝桥云课
题目大意:

现在有一条x轴,你位于坐标原点,现在有n个矿物都在x轴上,给出这n个矿物的横坐标,
你现在最多可以移动m次,请问你在最多m次移动的情况下,能得到最多多少矿物
解题思路:

方法一: 枚举一边选的个数 + 排序 + 二分查找

我们把在右边的放在一个数组,把在左边的放在另一个数组,并且取绝对值
然后呢,枚举选的个数
左边选0个
左边选一个,然后剩下的选右边
左边选两个,然后剩下的选右边
....
枚举完左边的,我们再枚举选右边的
右边选0个,剩下选左边的
右边选1个,剩下选右边的
...
 
可以使用排序后,用二分查找快速查找剩下可以选择的个数
具体过程可以看代码
时间复杂度,排序为O (n log n) , 枚举过程有二分,时间复杂度为O (n log n )
总体的时间复杂度为O (n log n)
代码(C++):

  1. #include <bits/stdc++.h>
  2. int main() {
  3.     int n, m;
  4.     std::cin >> n >> m;
  5.     std::vector<int> a, b;
  6.     for (int i = 0; i < n; i++) {
  7.         int v;
  8.         std::cin >> v;
  9.         if (v > 0) {
  10.             a.push_back(v);
  11.         } else {
  12.             b.push_back(abs(v));
  13.         }
  14.     }
  15.     std::sort(a.begin(), a.end());
  16.     std::sort(b.begin(), b.end());
  17.    
  18.     int ans = 0;
  19.     for (int r = 0; r <= a.size(); r++) {
  20.         int cost;
  21.         if (r == 0) {
  22.             cost = 0;
  23.         } else {
  24.             cost = 2 * a[r - 1];
  25.         }
  26.         if (cost > m) {
  27.             break;
  28.         }
  29.         int l = std::upper_bound(b.begin(), b.end(), m - cost) - b.begin();
  30.         ans = std::max(ans, l + r);
  31.     }
  32.     for (int l = 0; l <= b.size(); l++) {
  33.         int cost;
  34.         if (l == 0) {
  35.             cost = 0;
  36.         } else {
  37.             cost = 2 * b[l - 1];
  38.         }
  39.         if (cost > m) {
  40.             break;
  41.         }
  42.         int r = std::upper_bound(a.begin(), a.end(), m - cost) - a.begin();
  43.         ans = std::max(ans, l + r);
  44.     }
  45.     std::cout << ans;
  46. }
复制代码
方法二:枚举移动距离 - 前缀和

此方法参考评论区题解
既然最大只能走m次,那么我们可以建立两个数组a, b,长度分别设置为(m + 1),分别储存大于0和小于0的每个位置所包罗的矿物数目
然后枚举移动距离:
左边走0步,剩下的走右边
左边走1步,剩下的走右边
..
那么怎么快速判定这个步数下能得到的矿物数目呢?
前缀和数组 (代码中,直接把原数组变成前缀和数组了)
具体过程看代码
时间复杂度o(n)
代码(C++):

  1. #include <bits/stdc++.h>
  2. int main() {
  3.     int n, m;
  4.     std::cin >> n >> m;
  5.     std::vector<int> a(m + 1), b(m + 1);
  6.     for (int i = 0; i < n; i++) {
  7.         int v;
  8.         std::cin >> v;
  9.         if (abs(v) <= m) {
  10.             if (v > 0) {
  11.                 a[v]++;
  12.             } else {
  13.                 b[abs(v)]++;
  14.             }
  15.         }
  16.     }
  17.     for (int i = 1; i < m + 1; i++) {
  18.         a[i] += a[i - 1];
  19.         b[i] += b[i - 1];
  20.     }
  21.     int ans = 0;
  22.     for (int i = 0; i < m; i++) {
  23.         if (m - 2 * i < 0) {
  24.             break;
  25.         }
  26.         int mx = std::max(a[i] + b[m - 2 * i], b[i] + a[m - 2 * i]);
  27.         ans = std::max(ans, mx);
  28.     }
  29.    
  30.     std::cout << ans;
  31. }
复制代码
题八:回笔墨符串 - 双指针

0回笔墨符串 - 蓝桥云课
题目大意:

给你一个字符串,你可以往字符串开头添加任意数目的”l“, "g", "b"
请问你是否可以使得字符串变成回笔墨符串
解题思路:


代码(C++):



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 IT评测·应用市场-qidao123.com (https://dis.qidao123.com/) Powered by Discuz! X3.4