[第十六届蓝桥杯 JavaB 组] 真题 + 经验分享

A:逃离高塔(AC)

这题就是简单的签到题,按照题意枚举即可。需要注意的是不要忘记用long用int的话会爆

📖 ++代码示例++:

java 复制代码
import java.io.*;
import java.util.*;
public class Main {
    public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static void main(String[] args) throws IOException{
        long sum = 0;
        for(long i = 1;i <= 2025;i++){
            long num = i * i * i;
            if(num % 10 == 3){
                sum++;
            }
        }
        System.out.println(sum);
    }
}
//快读模板不必在意
class Read{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException{
        while(!st.hasMoreTokens()){
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }
    int nextInt() throws IOException{
        return Integer.parseInt(next());
    }
    long nextLong() throws IOException{
        return Long.parseLong(next());
    }
    double nextDouble() throws IOException{
        return Double.parseDouble(next());
    }
}

📕 答案:202

B:消失的蓝宝(AC)

这题最开始尝试用暴力枚举 ,但后来跑了好长时间,又扩大了好多次范围,还是没能出结果 ,硬想了半天,觉得应该和最小公倍数有关

要知道,要找到一个最小数,使得同时能被 a 和 b 整除,那么这个数就是 a 和 b 的最小公倍数。

题目中要求找到一个 n,满足(n + a) % b == 0 && (n + b) % a == 0,那么只要我们找到 a 和 b 的最小公倍数 c,此时c满足 c % a == c % b == 0。

那么 因为 c % a == 0 可以知道 (c - a) % a == 0。
同理 因为 c % b == 0 可以知道 (c - b) % b == 0。

假设现在我们有一个 n 满足 (n + a) % b == 0 那么 (n + a) = (c - b)
同理 (n + b) % a == 0 那么 (n + b) = (c - a)

最终得到 n = c - a - b

📖 ++代码示例++:

java 复制代码
import java.io.*;
import java.util.*;
public class Main {
    public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static void main(String[] args) throws IOException{
        long a = 20250412;
        long b = 20240413;
        System.out.println((a * b / gcd(a,b)) - a - b);
    }
    public static long gcd(long a,long b){
        return b == 0 ? a : gcd(b,a % b);
    }
}
class Read{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException{
        while(!st.hasMoreTokens()){
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }
    int nextInt() throws IOException{
        return Integer.parseInt(next());
    }
    long nextLong() throws IOException{
        return Long.parseLong(next());
    }
    double nextDouble() throws IOException{
        return Double.parseDouble(next());
    }
}

📕 答案:409876661809331

C:电池分组(AC)

该题考察的是对异或操作符的理解,题中的要求是给定一个数组,让我们判断,这个数组是否能够分成两部分,使得"两部分的异或和相等"。

异或操作符:两个数字,二进制位相同为0,否则为1。

我们得清楚,不管如何划分数组,整个数组的"异或和"都是不变的,而如果数组能够分成"两个异或和相等的部分",也就意味着,最后再将这两部分的异或和进行异或,结果必然是等于0的。(数字相等,所有二进制位相同)

那么这两部分异或和的异或,所得到的结果,代表什么呢?没错,代表整个数组的异或和。

那么也就是说:如果能找到这样的两部分,则代表整个数组的异或和一定为0。

反过来想,如果一个数组的异或和为0,是否就能代表一定存在这样的两部分呢?

是一定的。因为如果一个数组异或和为0,则代表最后的一步异或和,一定会是"两部分数组的异或和"进行异或,并且"这两部分的异或和一定相等",否则就违背了"整个数组异或和为0"的前提了。

所以:如果整个数组异或和为0,则输出"YES",否则,输出"NO"。

📖 ++代码示例++:

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static void main(String[] args) throws IOException {
        int t = in.nextInt();
        while(t-- > 0){
            int n = in.nextInt();
            int[] arr = new int[n];
            for(int i = 0;i < n;i++){
                arr[i] = in.nextInt();
            }
            long sum = arr[0];
            for(int i = 1;i < n;i++){
                sum = arr[i] ^ sum;
            }
            System.out.println(sum == 0 ? "YES" : "NO");
        }
    }
}
class Read{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException{
        while(!st.hasMoreTokens()){
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }
    int nextInt() throws IOException{
        return Integer.parseInt(next());
    }
    long nextLong() throws IOException{
        return Long.parseLong(next());
    }
    double nextDouble() throws IOException{
        return Double.parseDouble(next());
    }
}

D:魔法科考试(AC)

该题考察的是"素数筛法",这边我采用的是最常用的"埃氏筛",这题的数据范围是:

所以说我们只需要筛到大于40000的范围就好了,当然,即使这个范围不大,不使用优化筛法的话肯定也还是会超时的。因为使用双重for循环去检查所有魔法组合就已经有O(n^2)了~

注意:1 + 6 和 3 + 4 和 4 + 3,这种结果相同的"魔法口诀",算是同一个,不能重复计数,所以应该去重。

📖 ++代码示例++:

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static int[] zhi = new int[50100];
    public static boolean[] check = new boolean[50100];
    public static HashSet<Integer> set = new HashSet<>();
    public static void main(String[] args) throws IOException {
        shai();
        int a = in.nextInt();
        int b = in.nextInt();
        int[] arr1 = new int[a + 1];
        int[] arr2 = new int[b + 1];
        for(int i = 0;i < a;i++){
            arr1[i] = in.nextInt();
        }
        for(int i = 0;i < b;i++){
            arr2[i] = in.nextInt();
        }
        int max = 0;
        for(int i = 0;i < a;i++){
            for(int j = 0;j < b;j++){
                int num = arr1[i] + arr2[j];
                if(num <= a + b && zhi[num] == 1){
                    if(!set.contains(num)){
                        set.add(num);
                        max++;
                    }
                }
            }
        }
        System.out.println(max);
    }
    public static void shai(){
        for(int i = 2;i < 50049;i++){
            //未被筛出
            if(!check[i]){
                //标记为质数
                zhi[i] = 1;
                //将i的倍数都筛出
                for(int j = i;j < 50049;j += i){
                    check[j] = true;
                }
            }
        }
    }
}
class Read{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException{
        while(!st.hasMoreTokens()){
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }
    int nextInt() throws IOException{
        return Integer.parseInt(next());
    }
    long nextLong() throws IOException{
        return Long.parseLong(next());
    }
    double nextDouble() throws IOException{
        return Double.parseDouble(next());
    }
}

E:爆破

这题考察的应该是最小生成树...俺不会,写的dijkstra,运气好的话希望能骗个一两分吧...

F:数组翻转(AC)

++数据范围++:

我们先考虑++暴力解法++:

其实就是将所有可能的翻转都尝试一遍,这样就能找到所有的情况,并且找出最大的。

但翻转这个操作本身就是O(n)的 ,再加上尝试所有范围翻转,就达到了O(n^3),这是非常可怕的

(即使如此也能暴力掉20%,也就是3分,接近一道填空题的分数了~)

但实际上,我们并不需要进行"翻转"这个操作,因为:

翻转数组的目的是:得到可通过拼接得到的最长目标值。

而我们再想一下,如何能知道"可拼接得到的最长目标值串"呢?其实,就是找到整个数组中,"等于目标值的最长子串"和"等于目标值的第二长子串"进行拼接即可。

如何证明?其实很好想,不管如何选取范围翻转,我们都没法改变范围内数组的本质顺序,也就是说,我们只能"选取部分进行拼接",而每次拼接,肯定只能选到两个子串拼接,如果想选三个,那么势必会有两个子串中有间隔。

所以,我们只需要找到"每个值对应数组中的第一长与第二长子串",将长度相加后,进行求分数即可,最后找到"子串拼接后分数最高的值",输出即可。

java 复制代码
import java.util.*;
import java.io.*;

public class Main {
    public static PrintWriter pr = new PrintWriter(new BufferedWriter(new OutputStreamWriter(System.out)));
    public static Read in = new Read();
    public static void main(String[] args) throws IOException{
        int n = in.nextInt();
        int[] arr = new int[n + 1];
        HashSet<Integer> set = new HashSet<>();
        for(int i = 1;i <= n;i++){
            arr[i] = in.nextInt();
            set.add(arr[i]);
        }
        arr[0] = Integer.MAX_VALUE;
        HashMap<Integer,Integer> map1 = new HashMap<>();
        HashMap<Integer,int[]> map2 = new HashMap<>();
        int l = 1;
        int r = 1;
        while(r <= n){
            int len = map1.getOrDefault(arr[l],0);
            int newlen = 0;
            while(r <= n && arr[l] == arr[r]){
                newlen++;
                r++;
            }
            if(len < newlen){
                len = newlen;
                map1.put(arr[l],len);
                map2.put(arr[l],new int[]{l,r});
            }
            l = r;
        }
        HashMap<Integer,Integer> map3 = new HashMap<>();
        l = r = 1;
        //再次进行查找数组中的[第二长子串],跳过第一长子串即可
        while(r <= n){
            //为val = arr[l]的最长字串
            if(map2.get(arr[l])[0] == l){
                l = map2.get(arr[l])[1];
                r = l;
                continue;
            }
            int len = map3.getOrDefault(arr[l],0);
            int newlen = 0;
            while(r <= n && arr[l] == arr[r]){
                newlen++;
                r++;
            }
            if(len < newlen){
                len = newlen;
                map3.put(arr[l],len);
            }
            l = r;
        }
        long max = 0;
        for(int a:set){
            //有可能不存在第二长子串
            int len = map1.get(a) + map3.getOrDefault(a,0);
            long num = len * 1l * a;
            max = Math.max(max,num);
        }
        System.out.println(max);
    }
}
class Read{
    StringTokenizer st = new StringTokenizer("");
    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    String next() throws IOException{
        while(!st.hasMoreTokens()) {
            st = new StringTokenizer(br.readLine());
        }
        return st.nextToken();
    }
    String nextLine() throws IOException{
        return br.readLine();
    }
    int nextInt() throws IOException{
        return Integer.parseInt(next());
    }
    long nextLong() throws IOException{
        return Long.parseLong(next());
    }
    double nextDouble() throws IOException{
        return Double.parseDouble(next());
    }
}

G:2的幂

这题不会...but!

所以我写的时候,先判断原数组是不是已经满足条件了,如果满足直接输出0,不满足直接输出-1...不知道能不能骗到分。

H:研发资源分配

范围:

不会...只会用全排列暴力骗分。


总的来说,感觉今年蓝桥杯的数学和贪心含量太高了...考前学了一堆算法,dijkstra,floyd,并查集,最近公共祖先...一个都没出呀,这就算了...二分,bfs,dfs都没出。有种学了半年砌砖,最后考我电焊的感觉.难受

相关推荐
江畔柳前堤3 小时前
大语言模型分布式训练:从并行策略到万卡工程的系统梳理
人工智能·分布式·深度学习·算法·目标检测·机器学习·语言模型
Forever Nore4 小时前
LeetCode 4 寻找两个正序数组的中位数 - 二分
算法·leetcode
罗西的思考5 小时前
【OpenClaw具身硬件】MiniClaw 阅读笔记---(1)基础
人工智能·算法·机器学习
蛋先生DX6 小时前
大模型参数存储格式揭秘:BF不是男朋友
深度学习·算法·llm
爱跳舞的烤冷面7 小时前
自学嵌入式第22天(数据结构——哈希)
数据结构·算法·哈希算法
猎嘤一号7 小时前
博弈论(Game Theory)的理论、算法与工程
人工智能·算法·安全·博弈论
月光船幽幽7 小时前
影子模式下保护 logits 不被修改
人工智能·python·算法
马拉AI7 小时前
腾讯开源 Agent 记忆系统,AI“换对话就忘”的问题有了新解法(附安装使用教程)
人工智能·算法·开源·科研
地平线开发者9 小时前
征程6工具链模型X86推理方式说明
算法
地平线开发者9 小时前
【征程6】校准量化中HistogramObserver解析
算法