做之前的真题就可以发现,蓝桥杯特别喜欢出找规律的题,但是我还是低估了官方的执念。本博客用于记录第一次蓝桥的过程,代码写的很烂,洛谷已经有的题解,这里不再赘述,只说自己遇到的问题。用于以后回顾和查找资料,毕竟自己总结的印象更深。
本博客,没有多少借鉴价值,基本全是暴力破解和吐槽。
试题 **A:**移动距离 (填空 5分)
洛谷链接:P12130 [蓝桥杯 2025 省 B] 移动距离 - 洛谷

我不会,豆包说"在平面直角坐标系中,从原点(0,0)到点(x,y) ,如果先沿x轴正方向移动到(x,0) ,再沿以原点为圆心,半径为x2+02=x的圆移动到(x,y) ,这种移动方式的总距离最短。" ,但是我没有理解。
豆包代码:
cpp
#include <iostream>
#include <cmath>
using namespace std;
int main() {
double x = 233;
double y = 666;
double r = sqrt(x * x + y * y);
double distance = r + r * atan(y / x);
cout << distance << endl;
// 四舍五入到整数
int result = round(distance);
cout << result << endl;
return 0;
}
试题 **B:**客流量上限(填空 5分)
洛谷链接:P12131 [蓝桥杯 2025 省 B] 客流量上限 - 洛谷
比赛的时候,感觉是有什么规律的,我一直在思考如何保证2025个分店的客流量上限不同,感觉dfs可以,但是又不知道如何判断和
的乘积不得超过 i× j+ 2025,故作罢。
在洛谷上,看到大佬的题解,思路特别好:(P12131 [蓝桥杯 2025 省 B] 客流量上限 - 洛谷):
cpp
#include <bits/stdc++.h>
using namespace std;
int main(){
int n;
cin >> n;
vector<int> a;
for(int i=1;i<=n;i++){
a.push_back(i);
}
long long cnt=0;
do{
bool flag=true;
for(int i=0;i<n;i++){//位置
for(int j=0;j<n;j++){//位置
if(a[i]*a[j]>(i+1)*(j+1)+n){
//printf("%d %d\n",a[i],a[j]);
flag=false;
i=n;
break;
}
}
}
if(flag){
cnt++;
cnt%=1000000007;
}
}while(next_permutation(a.begin(),a.end()));
cout << cnt;
}
1 1
2 1
3 2
4 2
5 4
6 4
7 8
8 8
"1、1、2、2、4、4、8、8",发现次数等于
只需要再根据规律,算出结果即可。
cpp
#include<bits/stdc++.h>
using namespace std;
int main() {
int n;
cin >> n;
long long flag=(n-1)/2;
long long sum=1;
for (int i = 0; i < flag; i++)
{
sum*=2;
sum%=1000000007;
}
cout << sum << endl;
return 0;
}
试题 **C:**可分解的正整数(10分)
洛谷链接:P12132 [蓝桥杯 2025 省 B] 可分解的正整数 - 洛谷

【输入格式】
输入的第一行包含一个正整数 N ,表示数据的个数。
第二行包含 N 个正整数 A 1 , A 2 , . . . , A N ,表示需要判断是否可分解的正整数
序列。
【输出格式】
输出一个整数,表示给定数据中可分解的正整数的数量。
【样例输入】
3
3 6 15
【样例输出】
3
【样例说明】
A i = 3 是可分解的,因为 [0 , 1 , 2] 的和为 0 + 1 + 2 = 3 。
A i = 6 是可分解的,因为 [1 , 2 , 3] 的和为 1 + 2 + 3 = 6 。
A i = 15 是可分解的,因为 [4 , 5 , 6] 的和为 4 + 5 + 6 = 15 。
所以可分解的正整数的数量为 3 。
【评测用例规模与约定】
对于 30 % 的评测用例, 1 ≤ N ≤ 100 , 1 ≤
≤ 100 。
对于 100 % 的评测用例, 1 ≤ N ≤, 1 ≤
≤
。
这道题再知乎上也被很多人吐槽了,除了1全部可以。我的思路是从找规律开始,找他的样例:
0+1+2 = 3
1+2+3 = 6
2+3+4 = 9
会发现长度为三的序列可以输出所有三的倍数,所以只要是3的倍数都可以分解。
但是要注意题目条件是"序列长度至少为3 ",那如果长度为4,就是4的倍数也全部可分解,长度为5,就是5的倍数可以分解......这样下去,岂不是所有正整数都可以。恰好 "1 ≤ ≤
"。
而且可以有负数,那么...:
-1 + 0 + 1 + 2 = 2
-2 + -1 + 0 + 1 + 2 + 3 = 3
这样下去就是除了1,都可以"因为不能"-1+0+1+1"。
故找到规律后代码就很简单了,相信大家都知道怎么写了,但是我犯了一个很蠢的错误:
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n=0;
long long flag=0;
scanf("%d",&n);
for(int i=0;i<n;i++)
{
scanf("%lld",&flag);
if(flag==1)
n--;
}
printf("%d",n);
return 0;
}
大家可以看一下是什么问题,下面是通过的代码:
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n=0;
long long flag=0;
scanf("%d",&n);
for(int i=n;i>0;i--)
{
scanf("%lld",&flag);
if(flag==1)
n--;
}
printf("%d",n);
return 0;
}
试题 **D:**产值调整(10分)
洛谷链接:P12133 [蓝桥杯 2025 省 B] 产值调整 - 洛谷

【输入格式】
输入的第一行包含一个整数 T ,表示测试用例的数量。
接下来的 T 行,每行包含四个整数 A , B , C , K ,分别表示金矿、银矿和
铜矿的初始产值,以及需要执行的调整次数。
【输出格式】
对于每个测试用例,输出一行,包含三个整数,表示经过 K 次调整后金
矿、银矿和铜矿的产值,用空格分隔。
【样例输入】
2
10 20 30 1
5 5 5 3
【样例输出】
25 20 15
5 5 5
【评测用例规模与约定】
对于 30 % 的评测用例, 1 ≤ T ≤ 100 , 1 ≤ A , B , C , K ≤
。
对于 100 % 的评测用例, 1 ≤ T ≤ 10 5 , 1 ≤ A , B , C , K ≤。
看到这道题,思路不难,那就可能会出现超时问题,那就代表可能有规律,但是我没看出来,所以就先写出暴力解法看看:
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
long long A,B,C,K;
for(int j=0;j<n;j++)
{
scanf("%lld%lld%lld%lld",&A,&B,&C,&K);
int flag_A=A;
int flag_B=B;
int flag_C=C;
for(int i=0;i<K;i++)
{
A=(flag_B+flag_C)/2;
B=(flag_A+flag_C)/2;
C=(flag_A+flag_B)/2;
flag_A=A;flag_B=B;flag_C=C;
}
printf("%lld %lld %lld\n",A,B,C);
}
return 0;
}
运行例题通过了,那么就稍微改一下样例试试,加大看看是否超时:
2
10 20 30 50
5 5 5 30
结果为:
18 18 18
5 5 5
!!发现两组数A、B、C都相同,再让它输出中间值发现,除了前几次运算A、B、C不同,后边运算全相同,再换几个数也发现同样的规律。
故我想到的便是在三个数相同的时候跳出循环,这就是本题的答案:
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
int n;
scanf("%d",&n);
long long A,B,C,K;
for(int j=0;j<n;j++)
{
scanf("%lld%lld%lld%lld",&A,&B,&C,&K);
int flag_A=A;
int flag_B=B;
int flag_C=C;
for(int i=0;i<K;i++)
{
A=(flag_B+flag_C)/2;
B=(flag_A+flag_C)/2;
C=(flag_A+flag_B)/2;
flag_A=A;flag_B=B;flag_C=C;
if(A==B&&B==C&&A==C)
{
// printf("yes\n");
break;
}
// printf("A=%d B=%d C=%d\n",A,B,C);
}
printf("%lld %lld %lld\n",A,B,C);
}
return 0;
}
试题 **E:**画展布置 (15分)
洛谷链接:P12134 [蓝桥杯 2025 省 B] 画展布置 - 洛谷

【输入格式】
输入共两行。
第一行包含两个正整数 N 和 M ,分别表示画作的总数和需要挑选的画作数量。
第二行包含 N 个正整数 A 1 , A 2 , . . . , A N ,表示每幅画作的艺术价值。
【输出格式】
输出一个整数,表示 L 的最小值。
【样例输入】
4 2
1 5 2 4
【样例输出】
3
【评测用例规模与约定】
对于 40 % 的评测用例, 2 ≤ M ≤ N ≤ 10 3 , 1 ≤ A i ≤
。
对于 100 % 的评测用例, 2 ≤ M ≤ N ≤ 10 5 , 1 ≤ A i ≤。
这道题思路洛谷上题解也已经讲的很清楚(P12134 [蓝桥杯 2025 省 B] 画展布置 - 洛谷),我再做的时候遇到一个问题:
cpp
#include <bits/stdc++.h>
using namespace std;
int data[100004]={0};
int main()
{
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&data[i]);
sort(data,data+n+1);
// for(int i=1;i<=n;i++)
// printf("%d ",data[i]);
// printf("\n");
long long sum=0,flag_min=0;
flag_min=data[m]*data[m]-data[1]*data[1];
for(int i=2;i+m-1<=n;i++)
{
// flag_min = min(flag_min,data[i+m-1]*data[i+m-1]-data[i]*data[i]);
sum=data[i+m-1]*data[i+m-1]-data[i]*data[i];
if(sum<flag_min)
flag_min=sum;
}
printf("%lld",flag_min);
return 0;
}
这套代码再VScode会报错的:""data" 不明确",这是因为头文件中包含了同名的函数"data"造成的,所以要把"int data[100004]={0};"放在main函数里面,或者重命名。
另外他也不能通过全部测试点:

这是因为类型问题: data是"int"型,而sum和flag_min是long long型;data改为"long long"类型,便全部通过了:
cpp
#include <bits/stdc++.h>
using namespace std;
int main()
{
long long data[100004]={0};
int n,m;
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)
scanf("%d",&data[i]);
sort(data,data+n+1);
// for(int i=1;i<=n;i++)
// printf("%d ",data[i]);
// printf("\n");
long long sum=0,flag_min=0;
flag_min=data[m]*data[m]-data[1]*data[1];
for(int i=2;i+m-1<=n;i++)
{
flag_min = min(flag_min,data[i+m-1]*data[i+m-1]-data[i]*data[i]);
}
printf("%lld",flag_min);
return 0;
}
试题 **F:**水质检测(15分)

【输入格式】
输入共两行,表示一个 2 × n 的河床。
每行一个长度为 n 的字符串,仅包含 '#' 和 '.' ,其中 '#' 表示已经存在的
检测器, '.' 表示空白。
【输出格式】
输出共 1 行,一个整数表示答案。
【样例输入】
.##.....#
.#.#.#...
【样例输出】
5
【样例说明】
其中一种方案:
.###....#
.#.######
增加了 5 个检测器
【评测用例规模与约定】
对于 100 % 的评测用例,保证 n ≤ 1000000 。
对于这道题,我一开始想到的是暴力,通过dfs,第一个水质检测器作为起点,最后一个作为终点。比赛的时候是能过案例,同时我也自己试了几组数据也都是通过的,我当时想到的可能会有几个超时的,毕竟是遍历。但是我在洛谷运行的时候,竟然有WA。:

代码如下:
cpp
#include <bits/stdc++.h>
using namespace std;
string str[2]={"\0"};
int flag_min=0;
int book[2][1000004]={0};
//int sum=0;
int beg_x=0,beg_y=0;
int end_x=0,end_y=0;
int up[2][2]={
0,1,/*右*/
1,0 /*下*/
};
void dfs(int x,int y,int sum)
{
if(x==end_x&&y==end_y)
{
// printf("sum=%d end!\n",sum);
if(sum<flag_min)
flag_min=sum;
return ;
}
else if(x>=2||y>=str[0].size())
return ;
if(book[x][y]==0)
for(int i=0;i<2;i++)
{
book[x][y]=1;
if(str[x][y]=='.')
sum++;
dfs(x+up[i][0],y+up[i][1],sum);
book[x][y]=0;
}
return ;
}
int main()
{
char c;
int n=0;
cin>>str[0]>>str[1];
flag_min=str[0].size()*2;
int flag=0;
for(int i=0;i<str[0].size();i++)
{
for(int j=0;j<2;j++)
{
// printf("begin_test!\n");
if(str[j][i]=='#')
{
flag=1;
beg_x=j;
beg_y=i;
// printf("%d %d\n",beg_x,beg_y);
break;
}
}
if(flag==1) break;
}
if(flag==0) printf("0");/*表示一个#都没有*/
else
{
flag=0;
for(int i=str[0].size()-1; i>=0;i--)
{
for(int j=1;j>=0;j--)
{
// printf("end_test!\n");
if(str[j][i]=='#')
{
flag=1;
end_x=j;
end_y=i;
// printf("%d %d\n",end_x,end_y);
break;
}
}
if(flag==1) break;
}
// /*min_road*/
dfs(beg_x,beg_y,0);
printf("%d",flag_min);
}
return 0;
}
先找出起终点,然后通过dfs遍历,像迷宫问题一样(万能搜索算法-CSDN博客) ,TLE在预料之中,但WA不再,所以我开始找问题,最后发现,问题出在dfs的遍历方向上,我只遍历了"左","上"连个方向,这种情况只适用于,起点在第一行的情况,但如果出现在第二行,便永远不能到达第一行了,所以我又加了一个向上的方向。
cpp
int up[3][2]={
{0,1}, /*右*/
{1,0}, /*下*/
{-1,0} /*上*/
};
得到如下结果:
在预料之中。洛谷大佬已经给出了正解:P12135 [蓝桥杯 2025 省 B] 水质检测 - 洛谷。这种解法我是真想不出来,所以便不强行解释了。目前就暴力解法了。
试题 **G:**生产车间(20分)
洛谷链接:P12136 [蓝桥杯 2025 省 B] 生产车间 - 洛谷
【输入格式】
输入共 n + 1 行。
第一行为一个正整数 n 。
第二行为 n 个由空格分开的正整数 w 1 , w 2 , ..., w n 。
后面 n − 1 行,每行两个整数表示树上的一条边连接的两个结点。
【输出格式】
输出共一行,一个整数代表答案。
【样例输入】
9
9 7 3 7 1 6 2 2 7
1 2
1 3
2 4
2 5
2 6
6 7
6 8
6 9
【样例输出】
8
【样例说明】
删掉结点 4 、 9 后生产线满足条件,根结点 1 每单位时间将打包出 8 单位
的成品。
【评测用例规模与约定】
对于 20 % 的评测用例, 2 ≤ n ≤ 100 。
对于 100 % 的评测用例, 2 ≤ n ≤ 1000 , w i ≤ 1000 。
这道题的树就已经难到我了,因为我当时已经忘了怎么构建树了,而且这是一个多叉树,还不是二叉树。所以考试的时候是通过邻接矩阵 加01背包构造的,代码如下:
cpp
#include<bits/stdc++.h>
using namespace std;
int dfs(int root,int x,vector<vector<int>> tree,vector<int> w,int n)
{
vector<vector<int>> data(x,vector<int>(w[root]+1,0));/*0-x*/
int first=0;
for(int j=1;j<=n;j++)
{
if(tree[root][j]==2)
{
first=j;
break;
}
}
for(int i=0;i<=w[root];i++)
{
if(i>w[i])
data[0][i]=w[i];
}
if(x==n)
for(int i=0;i<x;i++)
{
for(int j=0;j<=w[root];j++)
if(i<w[i])
data[i][j]=data[i-1][j];
else
data[i][j]=max(data[i-1][j],data[i-1][j-w[i]]+w[i]);
}
return data[x-1][w[root]];
}
int main()
{
int n;
scanf("%d",&n);
vector<vector<int>> tree(n+1,vector<int>(n,0));
vector<int> w(n+1,0);
for(int i=1;i<=n;i++)
{
scanf("%d",&w[i]);
}
for(int i=0,a=0,b=0;i<n-1;i++)
{
scanf("%d%d",&a,&b);
tree[a][b]=1;
// tree[a].push_back(b);
}
int sum=0,num=0;
for(int i=1;i<=n;i++)/*从叶到根*/
{
sum=0,num=0;
for(int j=1;j<=n;j++)/*从小到大寻找父节点*/
{
if(tree[j][i]==1)/*j为父节点*/
{
for(int k=1;k<=n;k++)/*遍历子节点*/
{
if(tree[j][k]==1)
{
num++;
tree[j][k]=2;
sum+=w[k];
}
}
if(sum>w[j])
{
w[j]=dfs(j,num,tree,w,n);
}
}
}
}
cout<<w[1];
return 0;
}
因为我连测试点都没过,不出所料一片红:

与上一题一样,暴力的解法应该只有AC和TLE,所以我又开始找错误之旅。
经过我的不断修改,我决定放弃上边这套烂代码,用邻接表代替邻接矩阵来写(邻接矩阵太麻烦),并且通过dfs搜索,来实现树的遍历,但依旧采用01背包的思路去做:代码如下:
cpp
#include <iostream>
#include <vector>
using namespace std;
const int N = 1010;
int n, w[N];
vector<int> g[N];/*邻接表*/
int f[N][N]={0};
// 深度优先搜索
void dfs(int u) {
// 叶节点情况(g[u].empty()为NULL 输出1),叶节点的材料产出就是其权值
if (g[u].empty()) {
f[u][w[u]] = w[u];
return;
}
// 对当前节点的每个子节点进行DFS
for (int i = 0; i < g[u].size(); i++) {
int v = g[u][i];
dfs(v);
}
for (int i = 1; i <= w[u]; i++)/*初始化*/
{
if(w[g[u][0]]<=i)
f[u][i]=w[g[u][0]];
}
for (int i = 1; i < g[u].size(); i++)/*物品*/
{
for (int j=w[u];j>=0;j--)/*背包*/
f[u][j]=max(f[u][j],f[u][j-w[g[u][i]]]+w[g[u][i]]);
}
}
int main() {
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> w[i];
}
for (int i = 1; i < n; i++) {/*邻接表*/
int a, b;
cin >> a >> b;
g[a].push_back(b);
}
dfs(1);
cout << f[1][w[1]] << endl;
return 0;
}
通过的测试点如下:

比上次多了两个,呃,但是我想的应该是除了AC就是TLE,这显然不满足。最后我发现了这个致命的问题,虽然用了动态规划,但动态规划只造成了局部最优(每一个父节点与它的子节点),局部最优不代表全局最优,现在应该算是贪心,所以应该还有一层动态规划。
这里又发现一个问题!!我们来看输入," 每行两个整数表示树上的一条边连接的两个结点**"假设为a,b;这里并没有说输入的两个数顺序是a是b的入度,或者a是b的出度。题目中也没有明确说明哪个是根节点,但样例中是1,所以我们只能推测小数在前,即为根节点和父节点,故修改输入代码:**
cpp
for (int i = 1; i < n; i++) {/*邻接表*/
int a, b;
cin >> a >> b;
if(a>b) swap(a,b);
g[a].push_back(b);
}
多过了一个测试点:

这两层动态规划是难到我了,我感觉应该是绕到坑里了,所以我就直接去看洛谷题解了。 关键词:树形DP、分组背包。
试题 **H:**装修报价(20分)
洛谷链接:P12137 [蓝桥杯 2025 省 B] 装修报价 - 洛谷

【输入格式】
第一行输入一个整数 N ,表示装修相关费用的项数。
第二行输入 N 个非负整数 A 1 , A 2 , . . . , A N ,表示各项费用。
【输出格式】
输出一个整数,表示所有可能的总和对 10 9 + 7 取余后的结果。
【样例输入】
3
0 2 5
【样例输出】
11
【样例说明】
对于输入样例中的三个数 A = [0 , 2 , 5] ,所有可能的运算符组合共有 9 种。
计算结果如下:
0 ⊕ 2 ⊕ 5 = 7 ,
0 ⊕ 2 + 5 = 7 ,
0 ⊕ 2 − 5 = − 3 ,
0 + 2 ⊕ 5 = 7 ,
0 + 2 + 5 = 7 ,
0 + 2 − 5 = − 3 ,
0 − 2 ⊕ 5 = − 7 ,
0 − 2 + 5 = 3 ,
0 − 2 − 5 = − 7 .
所有结果的总和为:
7 + 7 + ( − 3) + 7 + 7 + ( − 3) + ( − 7) + 3 + ( − 7) = 11
11 对 10 9 + 7 取余后的值依然为 11 ,因此,输出结果为 11 。
【评测用例规模与约定】
对于 30 % 的评测用例, 1 ≤ N ≤ 13 , 0 ≤
≤
。
对于 60 % 的评测用例, 1 ≤ N ≤ 10 3 , 0 ≤≤
。
对于 100 % 的评测用例, 1 ≤ N ≤ 10 5 , 0 ≤≤
。
通过dfs搜索,应该是能得到部分分的,但是考试时我没写这道题,因为我忘记了异或是什么。。。。dfs暴力我就不演示了,懒得写了。
AC题解,也是先找规律。。。具体可以看洛谷题解。正和负相互抵消了。
吐槽
感觉蓝桥杯的题更适合高中、初中的同学来写,今年都是些规律题,与CSP、CCSP差远了。而且今年的提交方式已经和计挑赛有的一拼了,只能提交,不能调试(模拟赛还能知道答案是否正确,到正式比赛却又换了)。