第17届蓝桥杯省赛题目及解析【B组】
各个题目地址
一.[蓝桥杯 2026 省 B] 青春常数
二.[蓝桥杯 2026 省 B] 双碳战略
三.[蓝桥杯 2026 省 B] 循环右移
四.[蓝桥杯 2026 省 B] 蓝桥竞技
五.[蓝桥杯 2026 省 B] LQ 聚合
六.[蓝桥杯 2026 省 B] 应急布线
七.[蓝桥杯 2026 省 B] 理想温度
八.[蓝桥杯 2026 省 B] 足球训练
gitee仓库地址
一. [蓝桥杯 2026 省 B]青春常数
题目描述

解题思路:
此题属于送分题,因为题目需要x<y所以x的取值就只能是0~ ⌊ N / 2 ⌋ \lfloor N/2 \rfloor ⌊N/2⌋,所以最后的答案就是 ⌊ N / 2 ⌋ \lfloor N/2 \rfloor ⌊N/2⌋+1
#include<iostream>
using namespace std;
int main()
{
long long a = 2026202520242023;
cout << a/2+1 << endl;
return 0;
}
其实我刚看到这题的时候不小心灵机一动从0开始遍历到N/2…哈
二. [蓝桥杯 2026 省 B]双碳战略
题目描述

解题思路
这一题填空题对于在考场上的我来说算是很难的了,基本上就没有什么思路,主要刷题的数量和做题的经验还是太少了,像遇到这种类型的题目的话因为是填空题所以直接打表+找规律
这里解释一下打表就是先通过题意用暴力或者其他方法解出一些当数据范围比较小时的答案,然后在这些数据范围小的答案里面去找整体的规律,就比如这一题题目上说的是找2026个灯的情况,我们就可以先找假如只有3盏灯或者4盏灯的情况的所有答案,再去找规律
首先就遇到了一个问题,怎么打表?其实只要理解清楚题意就不难想到当数据范围小一些时其实可以使用bfs来搜索出到达所有状态的最少步数,所以接下来就应该分析题目所给的条件来确定bfs里面的每一个状态需要如何到达
这里需要注意题目中说的主控系统必须严格按照“双向交替”的规则执行操作也就是说假设这一次执行完奇数次操作后(后面的灯全部状态反转)那下一次的操作就必须是要执行偶数次的操作根据这样的性质我们就可以:
对于当前的状态,枚举所有的路灯以该路灯为要操作的路灯i因为现在要找当前状态的下一步所以就要判断从初始状态到当前状态的步数,如果是奇数次那么要找的下一个状态就要执行偶数次状态的操作(反转前面灯的状态),如果是偶数就执行奇数次的操作(反转后面灯的状态)
bfs代码如下
void bfs()
{
int n;
cin >> n; //可以自定义一个灯的数量来打表找规律
vector<int> s(2026); //初始状态
queue<vector> q;
map<vector<int>, int> dist;
q.push(s);
dist[s] = 0;
while(q.size())
{
auto a = q.front(); q.pop();
for(int i = 0; i < n; i++){
auto tmp = a;
//判断初始状态到当前状态的步数
if(dist[a] % 2 != 0){
//为奇数 所以要执行偶数次的操作
for(int j = 0; j <= i; j++)
tmp[j]^=1; //将每个状态反转
}
else{
for(int j = i; j < n; j++)
tmp[j]^=1;
}
if(!dist.count(tmp)){
dist[tmp] = dist[a] + 1; //第一次到达tmp状态的步数就是最短步数
q.push(tmp);
}
}
} //while循环的括号
int ans = 0; //到所有状态步数的总和
for(auto t : dist){
auto v = t.first;
auto cnt = t.second;
ans += cnt;
for(int n : v){
cout << n << " ";
}
cout << "步数为:" << cnt << endl;
}
cout << ans << endl;
}
将代码放在一个完整的程序中运行就会发现
当n=3时:
步数:0 1 3 1 2 2 2 1
此时 0有1个 1有3个 2有3个 3有一个 即:1 3 3 1
当n=4时
步数:0 1 3 1 3 4 3 1 2 2 3 2 2 2 2 1
此时 0有1个 1有4个 2有6个 3有4个 4有1个 即:1 4 6 4 1
我们发现这刚好是杨辉三角形啊!!!
所以最后的结果就是:
∑
i
=
1
n
C
2026
i
∗
i
\sum_{i=1}^{n} C_{2026}^{i}*i
∑i=1nC2026i∗i
这个最后的就交给你们自己去计算啦,有代码需要参考的可以看我的gitee仓库
【gitee仓库地址】
三. [蓝桥杯 2026 省 B] 循环右移
题目描述

解题思路
这题其实有个条件2的限定就很简单了,作为第一道大题其实也就是送分题,题目中要求对其进行一次循环右移操作,得到的新子数组与原数组完全一致其实列举一下就会发现要满足条件二只有当数组全部的元素都相同是才会满足的,只要有一个是不同的那么它们循环右移得出来的就一定不会和之前的相同
所以对于每一组的数据,答案就是:
| y − x + 1 > 0 ? y − x + 1 : 0 ; y-x+1>0 ?y-x+1:0; y−x+1>0?y−x+1:0; |
|---|
| 因为比较简单就不过多解释,代码参考可以看我的gitee仓库 |
四. [蓝桥杯 2026 省 B] 蓝桥竞技
题目描述


解题思路
题目中说组成战队的条件就是需要有5个职业互不相同的人,或许有的人在考场上面第一个想到的是模拟,但是我们可以看一下这个数据范围就T*N最大都能到达10^8了,所以直接模拟肯定是不行的,所以就要有条件判断
定义一个sum记录全部人数的总和
条件一:sum%5==0
因为每次都是选5个人组成一个战队,所以要想最后没有剩余的人那么总人数一定要是5的倍数
记录所有职业中人数的最大值a
条件二:
s
u
m
/
5
>
=
a
sum/5>=a
sum/5>=a
由sum的定义就可以知道,sum/5其实就是能组成战队的数量,因为题目说了每个战队一个职业只能有一个人,所以要想将人全部分配完肯定是要满足任意一个职业的总人数不能比总战队数量更多,所以我们只需要判断职业人数最多的那个不大于总战队数量就可以了
代码实现
#include<iostream>
#include<queue>
#include<vector>
using namespace std;
int main()
{
int T;
cin >> T;
while (T--)
{
int n;
long long sum = 0, a = 0;
cin >> n;
for (int i = 1; i <= n; i++)
{
long long x;
cin >> x;
sum += x;
a = max(a, x);
}
if (sum % 5 != 0)
{
cout << "F" << endl;
continue;
}
if (a <= sum / 5) cout << "T" << endl;
else cout << "F" << endl;
}
return 0;
}
五. [蓝桥杯 2026 省 B] LQ 聚合
题目描述


解题思路
根据题意需要修改字符串中的’?'来使得整个字符串的前’L’后‘Q’的对数最多(乘积最大) 也就是只能改变’?’
因为题目要求最大的LQ的对数,我们先不考虑’?‘之外的位置,假设我现在字符串中有6个’?'需要去填,为了能保证LQ最大我们是不是至少应该要保证在我能改变的地方L一定要在Q的后面因为L如果在Q的后面了LQ的对数是一定会小于L在Q的前面的
以下是证明:
就以此时红框中的L为例,此时它所能匹配到的LQ对数是3对,此时我将它和后面任意一个Q来交换位置
我们会发现此时不仅原来的L能匹配的LQ对数减少到了1对,就连下图中蓝色的L所能匹配的LQ对数也减少了
所以假设字符串里面只有6个’?‘那么最优的’?'排列结果一定是以下的几种情况
- Q Q Q Q Q Q
- L Q Q Q Q Q
- L L Q Q Q Q
- L L L Q Q Q
- L L L L Q Q
- L L L L L Q
- L L L L L L
所以我们最终的解题思路就是枚举这几种状态,求出每种状态的LQ对数,取出最大的LQ对数就可以了
这里讲一下代码的思路:
1)首先用一个临时变量t将第一种情况中LQ对数记录起来,还要赋值给最后的答案ans
2)用第一种情况创建Q的后缀数组sq(sq[ i ]即从最后一个位置到i位置一共出现了多少次Q)
3)遍历整个字符串用变量cur记录已经出现过的L的数量,每当遇到一个’?‘我们就可以看成将这个’?'改成了L所以此时整个字符串的LQ对数是
t
−
c
u
r
+
s
q
[
i
+
1
]
t-cur+sq[i+1]
t−cur+sq[i+1]再拿这个新的LQ对数维护ans的值(取最大)
代码实现
注:代码中的变量名字不和上面讲解的完全一样
#include<iostream>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10;
int sq[N];///后缀和数组
int main()
{
int n;
string s;
cin >> n >> s;
s = " " + s;
int cntL = 0;
LL cur = 0;
//初始时先把所有的‘?’当成Q
for (int i = 1; i <= n; i++)
{
if (s[i] == 'L') cntL++;
else
{
cur += cntL; //先算出所有问号都是Q的情况
}
}
LL ret = cur;
//计算Q字符出现次数的后缀和
for (int i = n; i >= 1; i--)
{
sq[i] = sq[i + 1];
if (s[i] != 'L') sq[i]++;
}
cntL = 0;
for (int i = 1; i <= n; i++)
{
if (s[i] == 'L') cntL++;
else if(s[i]=='?')
{
//将原本的Q替换成L 所以需要减去原先Q匹配的前面的L
cur -= cntL;
cur += sq[i + 1];
cntL++;
ret = max(ret, cur);
}
}
cout << ret;
return 0;
}
六. [蓝桥杯 2026 省 B] 应急布线
题目描述



解题思路
这题的第一问就是一个最普通的并查集主要的坑点在于第二问但是如果理解了的话第二问也是很简单的
这里大概讲一下并查集
并查集的作用:
(1)查找某个元素在哪个集合中
(2)判断两个元素是否属于同一个集合
(3)将两个元素所在的集合合并成一个集合(这里注意是将它们所在的集合合并成一个集合,不是将两个元素合并成一个集合)
并查集的实现
并查集的实现原理主要是用树来表示集合,使用一个数组就可以存储所有的元素,然后存储的方式使用双亲表示法存储,每个元素都存储它们的父亲节点,还有一点很重要的是并查集中每个集合都是由一个确定的元素代表的,因为是树来存储所以自然就是这个树的根节点来代表这个集合
以下是并查集的模板
#include<iostream>
using namespace std;
const int N = 2e5 + 10;
int fa[N];
//初始化
void ini(int n)
{
for (int i = 1; i <= n; i++)
{
fa[i] = i;
}
}
//查询
int find(int x)
{
if (x == fa[x]) return x;
return fa[x] = find(fa[x]);
}
//将x所在集合与y所在集合合并起来
void un(int x, int y)
{
int fx = find(x);
int fy = find(y);
fa[fx] = fy;
}
//判断两个元素是否属于同一个集合
bool issame(int x, int y)
{
return find(x) == find(y);
}
注:这里还放了一道并查集模板题供给不熟悉并查集的读者练习巩固
【模板】并查集
题目中无非就是还留有网线相连的两台电脑合并在一个集合里面,最后可以得出来一共有多少个集合n那么需要的最少的网线数量就是k=n-1
题目中说的确保跳线总数最少的前提下,单台计算机接入跳线数量最大值的最小可能值 这里定义每台电脑所连接的线的数量叫做度,我们发现假如要用一条线连接两台电脑是不是代表着这两台电脑的度各自都多了1如果将它们看成一个整体的话就是这个整体的度加了2

因为我们上面已经求出来了最少需要的跳线数量k,所以如果要加上k根线是不是就代表着这整个大集合的度加了2*k(也可以看成此时就有k * 2个度需要分配给所有的电脑) 所以要电脑最大接线数最少其实就是要将这 k * 2 个度平均分配给所有的电脑
所以最后的值就是: ⌈2 * k/n⌉
为了不让整篇文章过于的长所以这题的代码就放在我的gtiee仓库里面
【gtiee仓库地址】
当然如果有任何的建议都欢迎在评论区留言
七. [蓝桥杯 2026 省 B] 理想温度
题目描述

解题思路
对于所有评测用例,保证 1 ≤ n ≤ 2 × 10 5 1 \le n \le 2 \times 10^5 1≤n≤2×105, − 10 9 ≤ A i , B i ≤ 10 9 -10^9 \le A_i, B_i \le 10^9 −109≤Ai,Bi≤109。
首先我这里要给读者提醒千万要想到有些状态是初始时已经到达了理想温度了! 所以要记得考虑这种情况的限制
可能会有的读者在比赛时和我一样没有考虑到有的状态时已经到达了理想的温度了,就想到那这题不就是简单的求某个元素的最大的出现次数吗? 这样就是错的!因为可能区间里面有很多的已经达到理想温度的了所以直接这样求就属于是“假贪心”,情况没有考虑到位
这题应该不难想到可以先预处理一个数组
c
[
i
]
=
b
[
i
]
−
a
[
i
]
c[i]=b[i]-a[i]
c[i]=b[i]−a[i],
c
[
i
]
c[i]
c[i]代表的就是
i
i
i位置到达理想温度需要的温度,我们要让最多的传感器到理想温度其实就是要在某个区间加上一个
k
k
k值
在c数组上选择一个区间
[
l
e
f
t
,
r
i
g
h
t
]
[left,right]
[left,right]给区间每个传感器加
k
k
k温度那么在这个区间中
c
[
i
]
!
=
k
的地方对符合理想温度传感器的总数的贡献为
0
;
c
[
i
]
=
0
的贡献为
−
1
;
c
[
i
]
=
k
的贡献为
+
1
c[i] != k的地方对符合理想温度传感器的总数的贡献为0;c[i]=0的贡献为-1;c[i]=k的贡献为+1
c[i]!=k的地方对符合理想温度传感器的总数的贡献为0;c[i]=0的贡献为−1;c[i]=k的贡献为+1
其实主要的思路就是对于c[i]=0的地方它本就已经到达理想温度了,现在再加上k会导致符合理想温度的传感器减少1,所以它对到达理想温度传感器的总数的贡献就可以看成是-1,其他两种情况也是这样理解(本质上就是把它们看成0,1,-1的权值)
知道了上面的性质后现在的问题是:找到一个温度
k
k
k使得在某个区间加上这个温度
k
k
k可以让到达理想温度的传感器数量最多
由上面的性质我们可以根据
k
k
k值将数组转化成只有-1,0,1的数组,此时这个问题就转化成了找到一个温度
k
k
k使得转化后的数组的最大子段和最大
【最大子段和概念】给出一个长度为 n 的序列 a,选出其中连续且非空的一段使得这段和最大

上面转化后的数组代表的是在这个k值下每个位置对到达理想温度传感器总数的贡献
但是这个
k
k
k是不确定的,所以我们就可以采取枚举数组c中的所有值当作k
最终思路:枚举所有可能的k值算出每个k值转化后的数组的最大子段和,取其中的最大值即可
代码实现
#include<iostream>
#include<map>
using namespace std;
const int N = 2e5 + 10;
int c[N];
int n;
int main()
{
cin >> n;
for (int i = 1; i <= n; i++) scanf("%d", &c[i]);
for (int i = 1; i <= n; i++)
{
int b;
scanf("%d", &b);
c[i] = b - c[i];
}
int ret = 0, cur = 0; //ret是枚举k求最大子段和的最大值 cur当前位置0出现的次数
map<int, int> mn, cnt; //mn[k]代表的是以k为温度时最小的前缀和 cnt是k温度当前在c数中出现的次数
for (int i = 1; i <= n; i++)
{
int k = c[i];
if (k == 0) cur++;
else
{
if (!cnt.count(k)) mn[k] = cnt[k] - cur; //k第一次出现的话最小前缀和就是cnt[k] - cur
else mn[k] = min(mn[k], cnt[k] - cur); //时刻维护最小的前缀和
cnt[k]++;
ret = max(ret, cnt[k] - cur - mn[k]); //维护结果
}
}
//最后的结果是整个c数组0的总数+区间处理后得出来得新的到达理想温度传感器的数量
cout << cur + ret << endl;
return 0;
}
第八题作者自己也不是很会,有兴趣得读者可以再取研究一下
【第八题题目地址】
更多推荐





所有评论(0)