蓝桥杯 2025 Java B 组题解(省赛)
第一次参加蓝桥杯。用的是
BufferedReader
+PrintWriter
做输入输出,担心超时或者低级错误(比如Main
打成Mian
)。
次日更新,刚考完蜜汁自信,想着省一应该稳了,对完答案发现,填空全错,答题t到吐,大概15到20来分,省二估计都悬了,好好沉淀吧,大二奔国赛!
一、填空题
A. 立方和的个位数为 3 的数有几个?
思路
遍历 1~2025,每个数求立方,检查个位是不是 3。题目简单,我本来做对了,结果最后改错了(最后两分钟不开long重写一次,被自己蠢笑了),血亏 5 分。
Java代码
public class lan2025 {public static void main(String[] args) {int count = 0;for (long i = 1; i <= 2025; i++) {if (i * i * i % 10 == 3) {count++;}}System.out.println(count); // 答案是 202}
}
答案
202
B. 蓝宝不见了
题目条件
设 N 是蓝宝出现时间,满足:
N + 20250412
能被20240413
整除N + 20240413
能被20250412
整除- 求最小N
思路
我的思路是
但是他是一个什么什么定理,我也不懂,唉
Java代码
public class lan2025 {public static void main(String[] args) {int x = 20250412, y = 20240413;int c = x - y;for (int i = 1; i < 100000000; i++) {if (((x - c) * i - c) % x == 0) {long N = (long) (x - c) * i - x;System.out.println(N); // 答案break;}}}
}
答案
780002974133831(个人求解结果)
二、编程题
C. 电池分组(异或分组)
题目概述
研究员小蓝受到实验室主任的指示,需要对实验室新研发的 N N N 个新型能量电池进行分组实验。这 N N N 个能量电池的能量值分别用 A 1 , A 2 , … , A N A_1, A_2, \dots , A_N A1,A2,…,AN 表示,每个能量值都是一个整数。为了保证实验的安全性,小蓝需要将这 N N N 个能量电池分成两组,使得这两组能量电池的能量值异或和相等。
能量值的异或和计算方法如下:对于一个集合 S S S,其异或和等于集合中所有元素的按位异或结果。例如,集合 { 1 , 2 , 3 } \{1, 2, 3\} {1,2,3} 的异或和为 1 ⊕ 2 ⊕ 3 = 0 1 \oplus 2 \oplus 3 = 0 1⊕2⊕3=0,其中 ⊕ \oplus ⊕ 表示异或运算。
现在,小蓝想知道,这 N N N 个能量电池能否分成两组,使得这两组能量电池的能量值异或和相等。注意,每组至少包含一个能量电池。
输入格式
输入的第一行包含一个整数 T T T,表示测试用例的数量。
每个测试用例占两行:
- 第一行包含一个整数 N N N,表示能量电池的数量。
- 第二行包含 N N N 个整数 A 1 , A 2 , … , A N A_1, A_2, \dots , A_N A1,A2,…,AN,表示每个能量电池的能量值。
输出格式
对于每个测试用例,输出一行。如果可以将能量电池分成两组,使得这两组能量电池的能量值异或和相等,则输出 YES
;否则,输出 NO
。
输入输出样例 #1
输入 #1
2
3
1 2 3
4
1 2 3 4
输出 #1
YES
NO
解题思路
其实整组异或和为 0,就能分组成功(至少两组),不需要暴力回溯。
正确解法(简洁版)
public class Main {public static void main(String[] args) throws Exception {var br = new java.io.BufferedReader(new java.io.InputStreamReader(System.in));int T = Integer.parseInt(br.readLine());while (T-- > 0) {int n = Integer.parseInt(br.readLine());String[] parts = br.readLine().split(" ");int xor = 0;for (String s : parts) xor ^= Integer.parseInt(s);System.out.println(xor == 0 ? "YES" : "NO");}}
}
- 我是回溯,就过了一个用例
package lanqiao.lan2025;import java.io.*;
import java.util.HashSet;
import java.util.Set;public class q3 {static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) throws IOException {int t = Integer.parseInt(br.readLine());for(int i = 0;i<t;i++){int n = Integer.parseInt(br.readLine());int[] ans = new int[n];String[] s = br.readLine().split(" ");for(int j = 0;j<n;j++){ans[j] = Integer.parseInt(s[j]);}if(dfs(ans,0,new HashSet<>())){pw.println("YES");}else{pw.println("NO");}}pw.flush();}private static boolean dfs(int[] ans, int start, Set<Integer> set){if(start==ans.length){if(!set.isEmpty()){int a = 0;int b = 0;for(int i = 0;i<ans.length;i++){if(set.contains(i)){a^=ans[i];}else{b^=ans[i];}}if(a==b) {return true;}}return false;}boolean no = dfs(ans,start+1,set);set.add(start);boolean yes = dfs(ans,start+1,set);set.remove(start);return yes||no;}
}
D. 魔法科考试(有效魔法种类数)
题目描述
小明正在参加魔法科的期末考试,考生需要根据给定的口诀组合出有效的魔法。其中,老师给定了 n n n 个上半部分口诀 a 1 , a 2 , … , a n a_1, a_2, \dots , a_n a1,a2,…,an 和 m m m 个下半部分口诀 b 1 , b 2 , … , b m b_1, b_2, \dots , b_m b1,b2,…,bm,均用整数表示。完整的口诀包含一个上半部分口诀和一个下半部分口诀,当选用两个口诀 a i a_i ai 和 b j b_j bj,将组合出完整口诀 S = a i + b j S = a_i + b_j S=ai+bj。
当 S S S 满足 S ≤ n + m S \leq n + m S≤n+m 且 S S S 为质数时,魔法是有效的。魔法的种类只和 S S S 的大小有关。如果每个上半部分口诀和每个下半部分口诀在不同的组合中可以重复使用,小明想知道一共可能组合出多少种不同的有效魔法?
思路
- 枚举所有
a + b
。 - 若结果在
1 ~ (n + m)
范围内,且为质数,则是有效魔法。 - 用
Set
去重。
优化点
- 用布尔数组先筛出所有小于等于
n + m
的质数(埃氏筛)。
输入格式
输入共三行。
- 第一行为两个正整数 n , m n, m n,m。
- 第二行为 n n n 个由空格分开的正整数 a 1 , a 2 , … , a n a_1, a_2, \dots , a_n a1,a2,…,an。
- 第三行为 m m m 个由空格分开的正整数 b 1 , b 2 , … , b m b_1, b_2, \dots , b_m b1,b2,…,bm。
输出格式
输出共 1 1 1 行,一个整数表示答案。
输入输出样例 #1
输入 #1
3 4
2 3 10
3 4 5 1
输出 #1
3
Java代码
import java.io.*;
import java.util.*;public class Main {public static void main(String[] args) throws IOException {var br = new BufferedReader(new InputStreamReader(System.in));var s = br.readLine().split(" ");int n = Integer.parseInt(s[0]), m = Integer.parseInt(s[1]);int[] a = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();int[] b = Arrays.stream(br.readLine().split(" ")).mapToInt(Integer::parseInt).toArray();int max = n + m;boolean[] isPrime = new boolean[max + 1];Arrays.fill(isPrime, 2, max + 1, true);for (int i = 2; i * i <= max; i++) {if (isPrime[i]) {for (int j = i * i; j <= max; j += i)isPrime[j] = false;}}Set<Integer> valid = new HashSet<>();for (int x : a) {for (int y : b) {int sum = x + y;if (sum <= max && isPrime[sum]) {valid.add(sum);}}}System.out.println(valid.size());}
}
- 这里我又傻呗了,本来是打算用埃式筛,后面想想我的也应该不慢,又是t到吐,还是别太懒
import java.io.*;public class Main {static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) throws IOException {String[] s = br.readLine().split(" ");int n = Integer.parseInt(s[0]);int m = Integer.parseInt(s[1]);int[] ans1 = new int[n];int[] ans2 = new int[m];String[] s1 = br.readLine().split(" ");String[] s2 = br.readLine().split(" ");for(int i = 0;i<n;i++){ans1[i] = Integer.parseInt(s1[i]);}for(int i = 0;i<m;i++){ans2[i] = Integer.parseInt(s2[i]);}int count = 0;for(int i = 0;i<n;i++){for(int j = 0;j<m;j++){if(ans1[i]+ans2[j]<=n+m&&is(ans1[i]+ans2[j])){count++;}}}pw.println(count);pw.flush();}private static boolean is(int n){if(n<=1){return false;}if(n<=3){return true;}if(n%2==0||n%3==0){return false;}for(int i = 5;i*i<=n;i+=6){if(n%i==0||n%(i+2)==0){return false;}}return true;}
}
E. 爆破(最小生成树)
题目描述
小明正在参加一场爆破工作。人们在地面上放置了 n n n 个爆炸魔法阵,第 i i i 个魔法阵的圆心坐标为 ( x i , y i ) (x_i, y_i) (xi,yi),半径为 r i r_i ri。如果两个魔法阵相交,则它们可以一起引爆;如果两个魔法阵不相交,则可以再使用一条魔法回路将它们的边缘连接起来。小明想知道最少需要布置总长度多长的魔法回路才能使得所有的魔法阵可以一起引爆?
思路
其实就是找到能连通全部的一条线,我用的floyd哈哈哈哈哈,一样的t到吐
输入格式
输入共 n + 1 n + 1 n+1 行。
- 第一行为一个正整数 n n n。
- 后面 n n n 行,每行三个整数表示 x i , y i , r i x_i, y_i, r_i xi,yi,ri。
输出格式
输出共 1 1 1 行,一个浮点数表示答案(四舍五入保留两位小数)。
输入输出样例 #1
输入 #1
4
0 0 1
2 0 2
-3 0 1
4 4 1
输出 #1
2.47
Java代码(floyd)
import java.io.*;
import java.util.Arrays;public class Main {static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) throws IOException {int n = Integer.parseInt(br.readLine());double[][] grid = new double[n][n];double INF = 1e18; // 更安全的极大值for (double[] row : grid) {Arrays.fill(row, INF);}int[][] circles = new int[n][3];for (int i = 0; i < n; i++) {String[] s = br.readLine().split(" ");int x = Integer.parseInt(s[0]);int y = Integer.parseInt(s[1]);int r = Integer.parseInt(s[2]);circles[i] = new int[]{x, y, r};}for (int i = 0; i < n; i++) {grid[i][i] = 0;for (int j = i + 1; j < n; j++) {int dx = circles[i][0] - circles[j][0];int dy = circles[i][1] - circles[j][1];double dist = Math.sqrt(dx * dx + dy * dy);double cost = Math.max(0, dist - circles[i][2] - circles[j][2]);grid[i][j] = cost;grid[j][i] = cost;}}// Floyd-Warshall with overflow checkfor (int k = 0; k < n; k++) {for (int i = 0; i < n; i++) {for (int j = 0; j < n; j++) {if (grid[i][k] < INF && grid[k][j] < INF) {grid[i][j] = Math.min(grid[i][j], grid[i][k] + grid[k][j]);}}}}double max = 0;for (int i = 0; i < n; i++) {for (int j = i + 1; j < n; j++) {max = Math.max(max, grid[i][j]);}}pw.printf("%.02f\n", max); // 输出保留10位小数,防止精度误差pw.flush();}
}
F. 数组翻转最大得分
题目描述
小明生成了一个长度为 n n n 的正整数数组 a 1 , a 2 , … , a n a_1, a_2, \dots , a_n a1,a2,…,an,他可以选择连续的一段数 a l , a l + 1 , … , a r a_l, a_{l+1}, \dots, a_r al,al+1,…,ar,如果其中所有数都相等即 a l = a l + 1 = ⋯ = a r a_l = a_{l+1} = \dots = a_r al=al+1=⋯=ar,那么他可以获得 ( r − l + 1 ) × a l (r - l + 1) \times a_l (r−l+1)×al 的分数。
在选择之前,为了让分数尽可能大,他决定先选择数组中的一段区间,对其进行左右翻转。他想知道在对数组进行翻转之后他能获得的最大分数是多少?
提示:当翻转 a l a_l al 到 a r a_r ar 这段区间后,整个数组会变为:
a 1 , a 2 , … , a l − 1 , a r , a r − 1 , … , a l + 1 , a l , a r + 1 , … , a n a_1, a_2, \dots , a_{l-1}, a_r, a_{r-1}, \dots , a_{l+1}, a_l, a_{r+1}, \dots , a_n a1,a2,…,al−1,ar,ar−1,…,al+1,al,ar+1,…,an
输入格式
输入共两行。
- 第一行为一个正整数 n n n。
- 第二行为 n n n 个由空格分开的正整数 a 1 , a 2 , … , a n a_1, a_2, \dots , a_n a1,a2,…,an。
输出格式
输出共 1 1 1 行,一个整数表示答案。
输入输出样例 #1
输入 #1
7
4 4 3 3 2 1 3
输出 #1
9
Java暴力代码(t到吐):
import java.io.*;public class Main {static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) throws IOException {int n = Integer.parseInt(br.readLine());String[] s = br.readLine().split(" ");int[] ans = new int[n];for (int i = 0; i < n; i++) {ans[i] = Integer.parseInt(s[i]);}int maxArea = 0;for (int i = 0; i < n; i++) {for (int j = i; j < n; j++) {int[] copy = ans.clone();// reverse [i...j]for (int l = 0; l <= (j - i) / 2; l++) {int temp = copy[i + l];copy[i + l] = copy[j - l];copy[j - l] = temp;}maxArea = Math.max(maxArea, max(copy));}}pw.println(maxArea);pw.flush();}private static int max(int[] arr) {int max = 0;int i = 0;while (i < arr.length) {int j = i;while (j < arr.length && arr[j] == arr[i]) j++;max = Math.max(max, (j - i) * arr[i]);i = j;}return max;}
}
G. 2 的幂的倍数(最小加和)
题目描述
小明很喜欢 2 2 2 的幂,所以他想对一个长度为 n n n 的正整数数组 { a 1 , a 2 , … , a n } \{a_1, a_2, \dots, a_n\} {a1,a2,…,an} 进行改造。他可以进行如下操作任意多次(可以是 0 0 0 次):任选一个数 a i a_i ai 加上任意正整数,但不能使得加完之后的结果超过 1 0 5 10^5 105。
在操作任意次后,小明希望所有数的乘积是 2 k 2^k 2k 的倍数。他想知道总共需要加的数的总和至少是多少?
输入格式
输入共两行。
- 第一行为两个正整数 n , k n, k n,k。
- 第二行为 n n n 个由空格分开的正整数 a 1 , a 2 , … , a n a_1, a_2, \dots, a_n a1,a2,…,an。
输出格式
输出共 1 1 1 行,一个整数表示答案。如果不能满足条件,输出 − 1 -1 −1。
输入输出样例 #1
输入 #1
3 9
19 10 3
输出 #1
12
Java代码
// 比赛中我也是回溯暴力,不说了,说多都是累,而且我的还过不了用例,这里就不展示了
H. 研发资源分配最大差值(田忌赛马)
题目描述
在蓝桥科技公司, A A A 部门和 B B B 部门正在竞争一种新型 AI 芯片的研发资源。
为了公平分配资源,公司设计了一个为期 N N N 天的分配方案:
每天早上, A A A 部门和 B B B 部门各自提交一个需求等级(从 1 1 1 到 N N N 的整数)。提交等级较高的部门获得当天的资源,资源份额等于当天的日期编号(第 1 1 1 天为 1 1 1 单位,第 2 2 2 天为 2 2 2 单位,依次递增)。若两部门提交的等级相同,则当天资源作废,双方均无法获得资源。
每个部门必须在 N N N 天内使用 1 1 1 到 N N N 的所有等级,且每个等级只能使用一次。
有趣的是, A A A 部门在 B B B 部门内部安插了一名 “间谍”,提前获知了 B B B 部门的需求等级提交顺序,记为排列 ( P 1 , P 2 , … , P N P_1, P_2, \dots , P_N P1,P2,…,PN),其中 P i P_i Pi 表示 B B B 部门在第 i i i 天提交的需求等级。
现在,请你帮助 A A A 部门分析,在已知 B B B 部门需求等级顺序的情况下, A A A 部门的总资源份额减去 B B B 部门的总资源份额的差值最大可以是多少?
输入格式
第一行包含一个整数 N N N,表示分配方案的天数。
第二行包含 N N N 个整数 P 1 , P 2 , … , P N P_1, P_2, \dots , P_N P1,P2,…,PN,表示 B B B 部门在第 1 1 1 天到第 N N N 天提交的需求等级。
输出格式
输出一个整数,表示 A A A 部门的总资源份额减去 B B B 部门的总资源份额的最大差值。
输入输出样例 #1
输入 #1
3
1 3 2
输出 #1
2
思路
- A 部门可以按田忌赛马策略:用最小赢对方最大,用最大弃对方最强。
Java代码
import java.io.*;public class Main {static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));static PrintWriter pw = new PrintWriter(new OutputStreamWriter(System.out));public static void main(String[] args) throws IOException {int n = Integer.parseInt(br.readLine());int[] ans = new int[n];long count = 0;String[] s = br.readLine().split(" ");for(int i = 0;i<n;i++){ans[i] = Integer.parseInt(s[i]);if(ans[i]==n){count-=(i+1);}else{count+=(i+1);}}pw.println(count);pw.flush();}
}
总结
- 大家还是真的不要觉得暴力就完了,拿不了多少分的,而且我第一题还不对了,一开始还以为填空满分呢,被自己气笑了。
- 我是力扣300题水平,感觉没发挥好,但是走出来蜜汁自信,觉得全部暴力就好了,而且考场我也是一个十分放松的状态
- 痛定思痛,大二我将卷土重来,定个小小目标,国二!
- 祝大家能够取得自己心仪的成绩,加油加油!