2025年第十六届蓝桥杯省赛JavaB组真题回顾

2025年第十六届蓝桥杯省赛JavaB组真题回顾

 第16届蓝桥杯省赛已经结束了,第一次参加也是坐牢了4个小时,现在还是来总结一下吧(先声明以下的解法,大家可以当作一种思路来看,解法不一定是正解,只是给大家提供一种能够正常想到的思路吧)

试题A:逃离高塔

本题其实没有什么难度,就是一个循环遍历即可,那么唯一需要注意的就是循环遍历的过程中,int是会爆的,这里需要用long来进行存储
public class Main{ public static void main(String[] args){ int ans=0;//记录最终答案 for(long i=1;i<=2025;i++){ long x=i*i*i; if(n%10==3){ ans++; } } System.out.println(ans); } } ​
 最后进行的答案就是:202

 试题B:消失的蓝宝

这题其实也是循环遍历即可,但是我们不能一个数一个数的去试,如果一个一个去遍历的话,好像是要跑2小时是可以跑出来,那么通过题目我们可以发现:N+20250412要能够被20240413整除N+20240413要能够被20250412整除

上述表达式我们可以理解为,这个数一定是20240413的倍数,并且可以发现20250412比20240413是要大9999,那么我们可以设一个数 n1 初始为20240413,然后循环从20240413开始遍历,n1 每次都加上一个20240413(因为最后的结果一定是20240413的倍数,所以其他数就没有必要一个一个去遍历了),然后再循环中我们定义 n2=n1-9999,然后判断如果当前的 n2%20250412==0?(我们每次加的都是20240413,这个数肯定是20240413的倍数,则无需再判断n1%20240413==0?),如果等于0那么再减去一个20250412就是最终答案!(因为我们是第一个表达式为基准的,所以要减去一个20250412)
public class Main{ public static void main(String[] args){ for(long n1=20240413L;n1<Long.MAX_VALUE;n1+=20240413){ long n2=n1-9999; //判断 if(n2%20250412==0){ System.out.println(n1-20250412); break; } } } } 
最终答案就是:409876661809331 

 试题C:电池分组

这题就是一个位运算判断:要求将若干个数分为2组数字,那么这两组数字的异或和结果一样的话,一定是等于0的,这是为啥呢?举个例子:

例如样例的 1 2 3,1和2进行异或和后是3,那么3^3不就是0吗?所以我们只需要遍历一遍数组看看最后的异或结果是不是0即可(偷偷抱怨:这题这是太可惜了,考前1周都在学动态规划,考场看到这题还以为是01背包的选与不选的变种问题,最后还没写出来!!!)
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scan=new Scanner(System.in); int t=scan.nextInt(); while(t-->0){ int n=scan.nextInt(); int ans=0; for(int i=0;i<n;i++){ ans^=scan.nextInt(); } if(ans==0){ System.out.println("YES"); }else{ System.out.println("NO"); } } } } 

 试题D:魔法科考试

这题的考点就是判断素数的问题,其实就是两个循环遍历两个数组然后判断条件是否成立(需要的注意的是,这里会重复计算条件成立的同一个数,那么应该Set来过滤重复的数),再一个就是性能的问题,这里的数据是20000,如果使用朴素方法判断一个数是不是素数,那么最坏情况的时间复杂度就是n*m*log(a[i]+b[j]),这个时间复杂度是决定会超时的,在洛谷上这个时间复杂度是只能过8个案例的,所以我们应该提前筛好素数,然后在O(1)的时间复杂度判断是不是素数!(考场上我也没注意,使用的就是朴素的判断素数,这题也是拿不满的,可惜!!!)
import java.util.HashSet; import java.util.Scanner; import java.util.Set; public class Main{ static int[]prime=new int[20005]; static boolean st[]=new boolean[20005]; static int cnt=0; static Set<Integer> set=new HashSet<>(); static int num; public static void main(String[] args){ Scanner scan=new Scanner(System.in); int n=scan.nextInt(); int m=scan.nextInt(); int []a=new int[n]; int []b=new int[m]; for(int i=0;i<n;i++){ a[i]=scan.nextInt(); } for(int i=0;i<m;i++){ b[i]=scan.nextInt(); } num=n+m; //筛素数 creat(); //遍历枚举 int ans=0;//记录最终答案 for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ int s=a[i]+b[j]; if(s<=num){ //判断是不是素数 if(set.contains(s)){ ans++; set.remove(s); } } } } System.out.println(ans); } public static void creat(){ //这是只需要筛选出num以内的素数即可,因为超过num的素数我们根本判断不到 for(int i=2;i<=num;i++){ if(!st[i]){ prime[cnt++]=i; set.add(i); } for(int j=0;j<cnt;j++){ if(i*prime[j]>num)break; st[i*prime[j]]=true; if(i%prime[j]==0)break; } } } }

试题E:爆破

本题的核心就是在于,如何知道两个圆的最短距离:两个圆心之间的距离减去两个圆各自的半径,如果<=0那么就是相交的,如果不是那么就不是相交的

 画图分析:(画图画的不好请见谅)

import java.util.Scanner; public class Main{ static int g[][]; public static void main(String[] args) { Scanner scan=new Scanner(System.in); int n=scan.nextInt(); g=new int[n+1][3]; for(int i=1;i<=n;i++){ g[i][0]=scan.nextInt(); g[i][1]=scan.nextInt(); g[i][2]=scan.nextInt(); } //创建n*n的表格 double dp[][]=new double[n+1][n+1];//dp[i][j]表示第i个圆和第j个圆之间的距离 double ans=0;//存放最后答案 for(int i=1;i<=n;i++){ double min=Double.MAX_EXPONENT;//寻找当前圆和其他圆的最小距离 for(int j=1;j<=n;j++){ //判断第i个圆和第j个圆的距离 //先判断是不是自身 if(i==j){ dp[i][j]=Double.MAX_EXPONENT;//因为我们最后要求一个最小的值,所以这里赋最大值 }else{ dp[i][j]=func(i,j); } min=Math.min(min,dp[i][j]); } ans+=min; } System.out.printf("%.2f",ans); } //判断距离 public static double func(int i,int j) { //如果横坐标相同,直接判断纵坐标距离 if(g[i][0]==g[j][0]){ int len=Math.abs(g[i][1]-g[j][1]);//得到两个圆心的距离,再减去两个半径 len=len-(g[i][2]+g[j][2]); //判断是不是小于0.小于0就是相交的,距离就是0 return len<=0?0:len; } //如果纵坐标相同,直接判断横坐标的距离 if(g[i][1]==g[j][1]){ int len=Math.abs(g[i][0]-g[j][0]);//得到两个圆心的距离,再减去两个半径 len=len-(g[i][2]+g[j][2]); //判断是不是小于0.小于0就是相交的,距离就是0 return len<=0?0:len; } //此时是横纵坐标都不在一条线上,需要利用横纵坐标来结合勾股定理来得到两个圆心的距离 //我们以直角为基准,求两个临边的长度,然后通过勾股定理来求出对边(斜边)的长度 int lenx=Math.abs(g[i][0]-g[j][0]); int leny=Math.abs(g[i][1]-g[j][1]); //勾股 double len=Math.sqrt(lenx*lenx+leny*leny); //此时得到两个圆心的位置,然后再减去两个圆的半径 len=len-(g[i][2]+g[j][2]); return len<=0?0:len; } } 

试题F:数组翻转

本题呢本质上来说就是找两个最大的连续区间,暴力+优化

根据样例分析:

4 4 3 3 2 1 3 以样例为例就是最后变成4 4 3 3 3 1 2

那我们可以拓展一下 4 4 3 3 2 1 3 3 4 4 4

那就是4 4 4 4 4 3 3 1 2 3 3

我们会发现翻转的最佳效果是把连续并且相同的数最大的和第二大的合并在一起

 以下代码是暴力解法可能是会超时的(如果后续有更好的想法再做更新吧)

import java.util.Scanner; public class Main{ static boolean st[];//判断当前数是不是查找过 public static void main(String[] args) { Scanner scan=new Scanner(System.in); int n=scan.nextInt(); int[]a=new int[n]; int max=0; for(int i=0;i<n;i++){ a[i]=scan.nextInt(); max=Math.max(a[i],max); } st=new boolean[max+1]; long ans=0;//记录最终答案 for(int i=0;i<n;i++){ if(st[a[i]])continue;//此时说明当前数判断过了 int max1=0;//记录第一长的区间长度 int max2=0;//记录第二长的区间长度 int cnt=0; for(int j=i;j<n;j++){ if(a[j]==a[i]){ cnt++; }else{ //如果不是,那么我们记录一下之前的长度 if(cnt>max1){ max2=max1; max1=cnt; }else if(cnt>max2){ max2=cnt; } cnt=0; } } if(cnt!=0){ if(cnt>max1){ max2=max1; max1=cnt; }else if(cnt>max2){ max2=cnt; } } st[a[i]]=true; //此时统计两个最长区间 ans=Math.max(ans,1l*a[i]*(max1+max2)); } System.out.println(ans); } } 

试题G:2的幂

 本题暂时没有什么好的思路就先:略(如果有佬有想法可以评论在评论区)
... 

 

试题H:研发资源分配

 

这题读完题目感觉就是一个全排列求最大价值问题,但是直接dfs肯定是会超时的(只能过20%的案例),所以可以试试贪心策略,为了使 A 部门获得的资源尽可能多,B 部门获得的资源尽可能少,每天都让 A 部门提交比 B 部门当天提交等级刚好大 1 的等级(如果存在),如果没有更大的等级,就选择最小的等级,避免资源作废。如果都选择不了,那么就只能判断相等的数能不能相互抵消了
import java.util.Scanner; public class Main { public static void main(String[] args) { Scanner scanner = new Scanner(System.in); int n = scanner.nextInt(); int[] b = new int[n]; for (int i = 0; i < n; i++) { b[i] = scanner.nextInt(); } boolean[] used = new boolean[n + 1]; int sumA = 0; int sumB = 0; for(int i=0;i<n;i++){ //找出当前只比b[i]大一个的数 int index=-1;//默认没找到 int max=Integer.MAX_VALUE; for(int j=1;j<=n;j++){ if(j>b[i] && !used[j]){ //此时是找到了 index=j; used[j]=true; sumA+=i+1; break; } } //判断有没有找到 if(index==-1){ //此时说明没有找到,那么我们找最小的数 for(int j=1;j<=n;j++){ if(j<b[i] && !used[j]){ //此时是找到了 index=j; used[j]=true; sumB+=i+1; break; } } } //此时判断等于的情况 if(!used[b[i]] && index==-1){ //此时可以找到相同的 sumA+=0; sumB+=0; used[b[i]]=true; } } System.out.println(sumA-sumB); } }

总结

本次蓝桥杯相对前几届来说算法考的其实不多,主要还是逻辑思维问题, 我在考场上也只是做了一个填空和一个大题,大一第一次参加还是经验不够,总想着这题暴力肯定超时不愿意去写,一直坐在那里思考正解,但是这是非常不对的,我们应该先从暴力解开始优化才对,好歹写了还有一点分,再加上第一次参加肯定还是会紧张的,只能说明年继续努力吧!!!等到后面蓝桥云课加入了今年的题目,大家可以试试上述代码能通过几个案例哈(如果上述题解大佬们有更好的想法欢迎在评论区留言!!!)

Read more

【Java 开发日记】我们来说说 Redis 中 Zset 的底层实现

【Java 开发日记】我们来说说 Redis 中 Zset 的底层实现

目录 核心概括 一、两种编码方式 1. ziplist / listpack 编码 2. skiplist 编码 为什么需要两种结构? 二、核心数据结构剖析 1. 跳跃表(Skip List)详解 2. 字典(Dict) 三、操作流程示例 四、ZSET ZRANGE 操作序列图 五、总结与要点 面试回答 核心概括 Redis 的 Zset 同时具备两个核心特性: 1. 有序性:元素按分值(score) 从小到大排列。 2. 唯一性:集合中的成员(member) 是唯一的,但分值可以相同(分值相同时,按成员字典序排列)。 为了实现这种高效的、

By Ne0inhk
Java 注解与反射实战:手把手实现自定义日志与参数校验注解

Java 注解与反射实战:手把手实现自定义日志与参数校验注解

前言:为什么需要自定义注解? 在日常开发中,我们经常遇到两类重复工作: 日志记录:每个重要方法都要写 "开始执行"、"参数是 xxx"、"执行结束" 的代码;参数校验:判断输入是否为 null、年龄是否在合理范围、手机号格式是否正确等。 这些工作机械且冗余,而注解 + 反射正是解决这类问题的 "银弹"—— 用注解标记需要处理的地方,用反射自动执行逻辑,实现 "一次定义,多处复用"。 本文将带你从零实现两个实用案例: 1. 自定义日志注解@Log:自动记录方法调用细节; 2. 自定义参数校验注解@NotNull、@Range:自动校验方法参数合法性。 全程实战,代码可直接运行,搭配图解帮你吃透底层逻辑。 案例一:自定义日志注解@

By Ne0inhk
【Java String】类深度解析:从原理到高效使用技巧

【Java String】类深度解析:从原理到高效使用技巧

🎁个人主页:User_芊芊君子 🎉欢迎大家点赞👍评论📝收藏⭐文章 🔍系列专栏:【Java】内容概括 【前言】 在 Java 编程中,String 类是使用频率最高的类之一,也是初学者接触最早的引用类型之一。但正是因为其基础且常用,很多开发者往往忽略了它的底层原理和高级特性。本文将从 String 类的底层实现、核心方法到性能优化、常见误区,全方位解析 Java String 类,帮你彻底搞懂这一基础却关键的类。 文章目录: * 一、String类本质特征 * 1.String类定义 * 2.字符串创建及内存机制 * 3.字符串常量池(StringTable) * 二、String 类核心方法 * 1.字符串方法比较 * 1.1“==”比较是否引用同一个对象 * 1.2 equals

By Ne0inhk

Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=GBK 新版IDEA编码格式GBK问题 maven命令Picked up JAVA_TOOL_OPTION

📋 问题概述 问题现象 在使用新版IDEA执行 Maven 构建项目时,控制台输出警告信息: Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=GBK 🔍 问题排查过程 第一阶段:初步判断与假设 初始假设:系统环境变量设置了 Java 编码为 GBK 第二阶段:环境变量验证 cmd # 检查环境变量 echo %JAVA_TOOL_OPTIONS% # 输出:%JAVA_TOOL_OPTIONS%(表示变量未显式设置) 排查结果:系统环境中并未手动设置 JAVA_TOOL_OPTIONS 变量 第三阶段:深入排查IDEA配置 怀疑方向:IDEA内部设置或配置文件指定了GBK编码 检查项包括: 1. IDEA VM Options:

By Ne0inhk