[第十六届蓝桥杯 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都没出。有种学了半年砌砖,最后考我电焊的感觉.难受

相关推荐
爱的叹息1 小时前
【java实现+4种变体完整例子】排序算法中【基数排序】的详细解析,包含基础实现、常见变体的完整代码示例,以及各变体的对比表格
java·算法·排序算法
写个博客2 小时前
代码随想录算法训练营第二十一天
算法
美亚特直线轴承3 小时前
直线轴承在自动化机械设备中的应用
运维·人工智能·经验分享·笔记·机器人·自动化·制造
keep intensify4 小时前
杨氏矩阵、字符串旋转、交换奇偶位,offsetof宏
c语言·开发语言·数据结构·算法·矩阵
自由鬼6 小时前
AI当前状态:有哪些新技术
人工智能·深度学习·算法·ai·chatgpt·deepseek
奋进的小暄6 小时前
贪心算法(20)(java)整数替换
开发语言·算法
王齐家04067 小时前
每日一题算法——移除链表元素、反转链表
数据结构·算法·leetcode·链表
天天扭码7 小时前
一分钟解决 | 高频面试算法题——和为 K 的子数组(前缀和)
前端·算法·面试
ChoSeitaku7 小时前
NO.97十六届蓝桥杯备战|数论板块-最大公约数和最小公倍数|欧几里得算法|秦九韶算法|小红的gcd(C++)
c++·算法·蓝桥杯