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

华为OD技术面八股文_C++_01

华为OD技术面八股文_C++_01

文章目录 * C语言和C++的区别 * C++11引入哪些新特性 * 什么是面向对象?面向对象的三大特性 * malloc和new的区别 * delete和free的区别 * delete和delete[]的区别 * 什么是虚函数?什么是纯虚函数 * 什么是虚函数表?什么是虚函数指针? * 介绍一下虚函数实现机制 * 构造函数和构析函数能不能写为虚函数,为什么 * 说一下构造、析构函数的调用顺序 C语言和C++的区别 1. C++有新增的关键字和语法,还允许自定义命名空间。 2. C++新增类的概念,C语言中只有struct的概念。C++中添加访问权限概念,struct 的默认访问权限和继承权限都是 public,但是 class 的默认访问权限和默认继承权限都是 private. 3. C++引入了类、封装、继承、多态、模板、重载、异常处理机制等特性。而C没有 4.

By Ne0inhk
C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析

C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析

C++可变参数队列与压栈顺序:从模板语法到汇编调用约定的深度解析 本文聚焦一个具体而关键的技术主题:C++ 可变参数模板(Variadic Templates)。我们将从现代 C++ 的优雅写法出发,深入剖析其在 x86-64 架构下的真实行为,特别澄清一个长期被误解的核心问题——可变参数是否“从右向左压栈”?它们在寄存器和栈中究竟是如何排布的? 如果你正在实现一个类型安全的消息队列、日志系统或任务调度器,并希望理解 enqueue(1, "hello", 3.14) 这行代码在 CPU 层面到底发生了什么,那么这篇文章就是为你量身打造的。 一、引言:可变参数 ≠ va_list —— 一场范式革命 很多初学者将 C++ 的可变参数模板与 C 语言的 va_list 混为一谈。这是重大误区,甚至会导致错误的性能假设和安全漏洞。 1.1

By Ne0inhk
《C++ Stack 与 Queue 完全使用指南:基础操作 + 经典场景 + 实战习题》

《C++ Stack 与 Queue 完全使用指南:基础操作 + 经典场景 + 实战习题》

🔥草莓熊Lotso:个人主页 ❄️个人专栏: 《C++知识分享》《Linux 入门到实践:零基础也能懂》 ✨生活是默默的坚持,毅力是永久的享受! 🎬 博主简介: 文章目录 * 前言: * 一. 先搞懂基础:Stack 与 Queue 的核心特性 * 二. Stack(栈):后进先出(LIFO)的容器 * 2.1 核心特性: * 2.2 头文件与定义 * 2.3 常用接口全解析 * 2.4 基础用法演示 * 三. Queue(队列):先进先出(FIFO)的容器 * 3.1 核心特性: * 3.2 头文件与定义: * 3.

By Ne0inhk
【C++】第十七节—二叉搜索树(概念+性能分析+增删查+实现+使用场景)

【C++】第十七节—二叉搜索树(概念+性能分析+增删查+实现+使用场景)

好久不见,我是云边有个稻草人 《C++》本文所属专栏—持续更新中—欢迎订阅 目录 一、二叉搜索树的概念 二、二叉搜索树的性能分析 三、二叉搜索树的插入 SearchBinaryTree.h test.cpp 四、⼆叉搜索树的查找 【只有一个3】 【有多个3】  五、⼆叉搜索树的删除 六、二叉搜索树的实现代码 SearchBinaryTree.h test.cpp  七、二叉搜索树key和key/value使用场景 7.1 key搜索场景 7.2 key/value搜索场景 7.3 key/value⼆叉搜索树代码实现 .h .cpp 正文开始—— 一、二叉搜索树的概念 ⼆叉搜索树⼜

By Ne0inhk