【2024年蓝桥杯Java B组】省赛真题详细解析

发布于:2025-04-09 ⋅ 阅读:(59) ⋅ 点赞:(0)

【2024年蓝桥杯Java B组】省赛真题

距离比赛仅剩5天,大多数省份可能完成3-4题即可拿到省奖,2025年想要拿到省奖,需要高效利用时间,重点突破关键知识点和题型。这里以【2024年蓝桥杯Java B组省赛真题】为例,梳理我们最后5天重点需要攻克的题型~希望大家都可以顺利获奖!

第一题:报数游戏

  • 赛题:给定一个数列,第奇数项是20的倍数,第偶数项是24的倍数。求第n项的值,其中n=202420242024。
  • 解题思路:通过观察数列规律,发现第n项的值可以通过简单的数学公式计算得出。对于偶数项,答案是n/2乘以24。
  • 代码
    public class Main1 {
        public static void main(String[] args) {
            long n = 202420242024L;
            n /= 2;
            long a = 24;
            long ans = n * 24;
            System.out.println(ans);
        }
    }
    
  • 技巧:通过观察数列的规律,快速找到解题的公式,避免复杂的计算。

第二题:类斐波那契循环数

  • 赛题:给定一个数N,判断N是否是一个类斐波那契循环数。类斐波那契循环数是指一个数N可以出现在由其各位数字生成的类斐波那契数列中。
  • 解题思路:从最大的可能值10^7开始向下遍历,逐个判断每个数是否为类斐波那契循环数。通过模拟生成类斐波那契数列并判断N是否出现在其中。
  • 代码
    public class Main1 {
        static List<Integer> toList(int a) {
            List<Integer> list = new ArrayList<>();
            while (a > 0) {
                int t = a % 10;
                list.add(t);
                a /= 10;
            }
            Collections.reverse(list);
            return list;
        }
    
        static boolean isFab(int a) {
            ArrayList<Integer> list = new ArrayList<>(toList(a));
            int len = list.size();
            while (true) {
                int sum = 0;
                for (int i = list.size() - 1; i > list.size() - 1 - len; i--) {
                    sum += list.get(i);
                }
                if (sum == a) return true;
                if (sum > a) return false;
                list.add(sum);
            }
        }
    
        public static void main(String[] args) {
            int end = (int) 1e7;
            while (end > 0) {
                if (isFab(end)) {
                    System.out.println(end);
                    return;
                }
                end--;
            }
        }
    }
    
  • 技巧:通过模拟生成类斐波那契数列,逐个判断每个数是否满足条件,避免复杂的数学推导。

第三题:分布式队列

  • 赛题:模拟一个分布式队列的运行状态,主节点添加元素,副节点同步元素,查询当前具有可见性的元素数量。
  • 解题思路:通过维护一个数组记录每个副节点的同步状态,每次操作更新对应的状态,查询时计算所有副节点中同步到的最少元素数量。
  • 代码
    import java.util.Arrays;
    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            int[] index = new int[n];
            Arrays.fill(index, -1);
    
            while (sc.hasNextLine()) {
                String line = sc.nextLine();
                String[] tokens = line.split(" ");
                String s = tokens[0];
    
                if ("query".equals(s)) {
                    int min = Integer.MAX_VALUE;
                    for (int i : index) {
                        if (min > i) min = i;
                    }
                    System.out.println(min + 1);
                } else if ("add".equals(s)) {
                    int element = Integer.parseInt(tokens[1]);
                    index[0]++;
                } else if ("sync".equals(s)) {
                    int followerId = Integer.parseInt(tokens[1]);
                    if (followerId >= 1 && followerId < n) {
                        if (index[followerId] < index[0]) {
                            index[followerId]++;
                        }
                    }
                }
            }
        }
    }
    
  • 技巧:通过数组记录每个节点的同步状态。

第四题:食堂

  • 赛题:给定不同类型的寝室和食堂的桌子,安排寝室成员到食堂用餐,最大化同时用餐的学生人数。
  • 解题思路:通过贪心算法,优先安排满桌、小桌、人多的寝室,最后考虑空少的情况,逐步尝试不同的组合,计算最大用餐人数。
  • 代码
    import java.util.Scanner;
    
    public class Main {
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int q = sc.nextInt();
            while (q-- > 0) {
                int a2 = sc.nextInt();
                int a3 = sc.nextInt();
                int a4 = sc.nextInt();
                int b4 = sc.nextInt();
                int b6 = sc.nextInt();
    
                long ans = 0;
                int t;
    
                t = Math.min(a4, b4);
                ans += t * 4;
                a4 -= t;
                b4 -= t;
    
                t = Math.min(a2 / 2, b4);
                ans += t * 4;
                a2 -= t * 2;
                b4 -= t;
    
                t = Math.min(b6, Math.min(a4, a2));
                ans += t * 6;
                a4 -= t;
                a2 -= t;
                b6 -= t;
    
                t = Math.min(b6, a3 / 2);
                ans += t * 6;
                a3 -= t * 2;
                b6 -= t;
    
                t = Math.min(b6, a2 / 3);
                ans += t * 6;
                a2 -= t * 3;
                b6 -= t;
    
                t = Math.min(b6, Math.min(a3, a2));
                ans += t * 5;
                a3 -= t;
                a2 -= t;
                b6 -= t;
    
                t = Math.min(b4, a3);
                ans += t * 3;
                a3 -= t;
                b4 -= t;
    
                t = Math.min(b6, a4);
                ans += t * 4;
                a4 -= t;
                b6 -= t;
    
                t = Math.min(b6, a2 / 2);
                ans += t * 4;
                a2 -= t * 2;
                b6 -= t;
    
                t = Math.min(b4, a2);
                ans += t * 2;
                a2 -= t;
                b4 -= t;
    
                t = Math.min(b6, a3);
                ans += t * 3;
                a3 -= t;
                b6 -= t;
    
                t = Math.min(b6, a2);
                ans += t * 2;
                a2 -= t;
                b6 -= t;
    
                System.out.println(ans);
            }
        }
    }
    
  • 技巧:通过贪心算法,逐步尝试不同的组合,确保每一步都尽可能最大化用餐人数。

第五题:最优分组

  • 赛题:给定N个宠物和感染概率p,将宠物分组进行检测,最小化检测剂的期望消耗数量。
  • 解题思路:通过计算不同分组大小K的期望消耗数量,选择最小的期望值对应的K。
  • 代码
    import java.util.ArrayList;
    import java.util.Collections;
    import java.util.Scanner;
    
    public class Main {
        static int N, ans;
        static double p, min = Double.MAX_VALUE / 2;
        static ArrayList<Integer> factors = new ArrayList<>();
    
        static double calculateExpected(int K) {
            if (K == 1) return N;
            double probabilityAllNegative = Math.pow(1 - p, K);
            double expectedTestsPerGroup = probabilityAllNegative * 1 + (1 - probabilityAllNegative) * (1 + K);
            return expectedTestsPerGroup * ((double) N / K);
        }
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            N = sc.nextInt();
            p = sc.nextDouble();
    
            for (int i = 1; i <= Math.sqrt(N); i++) {
                if (N % i == 0) {
                    factors.add(i);
                    if (N / i != i) {
                        factors.add(N / i);
                    }
                }
            }
    
            Collections.sort(factors);
    
            for (int K : factors) {
                double currentExpected = calculateExpected(K);
                if (currentExpected < min) {
                    ans = K;
                    min = currentExpected;
                }
            }
    
            System.out.println(ans);
        }
    }
    
  • 技巧:通过数学期望的计算,选择最优的分组大小K。

第六题:星际旅行

  • 赛题:给定一个星系的星球和传送门,计算从某个星球出发,使用不超过一定次数的传送门,可以到达的星球数量的期望值。
  • 解题思路:通过Floyd-Warshall算法计算所有星球之间的最短路径,然后统计每个旅行方案可以到达的星球数量,计算期望值。
  • 代码
    import java.util.Scanner;
    
    public class Main {
        static long INF = Long.MAX_VALUE / 2;
    
        public static void main(String[] args) {
            long[][] g = new long[1010][1010];
            Scanner in = new Scanner(System.in);
            int n = in.nextInt();
            int m = in.nextInt();
            int q = in.nextInt();
    
            for (int i = 0; i < g.length; i++) {
                Arrays.fill(g[i], INF);
                g[i][i] = 0;
            }
    
            for (int i = 0; i < m; i++) {
                int u = in.nextInt();
                int v = in.nextInt();
                g[u][v] = 1;
                g[v][u] = 1;
            }
    
            for (int k = 1; k <= n; k++) {
                for (int i = 1; i <= n; i++) {
                    for (int j = 1; j <= n; j++) {
                        if (g[i][k] != INF && g[k][j] != INF) {
                            if (g[i][j] > g[i][k] + g[k][j]) {
                                g[i][j] = g[i][k] + g[k][j];
                            }
                        }
                    }
                }
            }
    
            long ans = 0;
            for (int i = 0; i < q; i++) {
                int start = in.nextInt();
                int k = in.nextInt();
                for (int j = 1; j <= n; j++) {
                    if (g[start][j] <= k) ans++;
                }
            }
            System.out.printf("%.2f", 1.0 * ans / q);
        }
    }
    
  • 技巧:通过Floyd-Warshall算法计算最短路径。

第七题:俄罗斯方块

  • 赛题:给定一个N×N的格子图,判断是否可以放置四种不同的俄罗斯方块图案,使得它们不重叠。
  • 解题思路:通过暴力枚举所有可能的图形排列组合,尝试放置每种图形,判断是否满足条件。
  • 代码
    import java.util.Scanner;
    
    public class Main {
        private static int[][][][] lits = {
            // L形状的4种旋转状态
            {
                {{0, 0}, {0, -1}, {-1, -1}, {-2, -1}},
                {{0, 0}, {-1, 0}, {-1, 1}, {-1, 2}},
                {{0, 0}, {-1, 0}, {-2, 0}, {-2, -1}},
                {{0, 0}, {0, -1}, {0, -2}, {-1, 0}}
            },
            // I形状的2种旋转状态
            {
                {{0, 0}, {-1, 0}, {-2, 0}, {-3, 0}},
                {{0, 0}, {0, -1}, {0, -2}, {0, -3}}
            },
            // T形状的4种旋转状态
            {
                {{0, 0}, {-1, 0}, {-1, -1}, {-1, 1}},
                {{0, 0}, {-1, 0}, {-2, 0}, {-1, -1}},
                {{0, 0}, {0, -1}, {0, -2}, {-1, -1}},
                {{0, 0}, {-1, 0}, {-2, 0}, {-1, 1}}
            },
            // S形状的2种旋转状态
            {
                {{0, 0}, {0, -1}, {-1, 0}, {-1, 1}},
                {{0, 0}, {-1, 0}, {-1, -1}, {-2, -1}}
            }
        };
    
        static int[] pos = new int[4];
        static boolean flag = false;
        static boolean[] vis = new boolean[4];
    
        static boolean success() {
            for (boolean t : vis) if (!t) return false;
            return true;
        }
    
        static void fill(int x, int y, int k, int[][] map, int val) {
            for (int i = 0; i < 4; i++) {
                int xx = x + lits[k][pos[k]][i][0];
                int yy = y + lits[k][pos[k]][i][1];
                map[xx][yy] = val;
            }
        }
    
        static boolean check(int x, int y, int k, int[][] map) {
            int N = map.length;
            for (int i = 0; i < 4; i++) {
                int xx = x + lits[k][pos[k]][i][0];
                int yy = y + lits[k][pos[k]][i][1];
                if (xx >= N || xx < 0 || yy >= N || yy < 0 || map[xx][yy] != 1) return false;
            }
            return true;
        }
    
        static void dfs(int x, int y, int[][] map) {
            int N = map.length;
            if (success()) {
                flag = true;
                return;
            }
    
            if (flag || x == N) return;
    
            if (y == N) {
                dfs(x + 1, 0, map);
                return;
            }
    
            if (map[x][y] != 1) {
                dfs(x, y + 1, map);
                return;
            }
    
            for (int i = 0; i < 4; i++) {
                if (!vis[i] && check(x, y, i, map)) {
                    fill(x, y, i, map, 2);
                    vis[i] = true;
    
                    dfs(x, y + 1, map);
                    if (flag) return;
    
                    fill(x, y, i, map, 1);
                    vis[i] = false;
                }
            }
            dfs(x, y + 1, map);
        }
    
        static boolean solve(int[][] map) {
            for (int l = 0; l < 4; l++) {
                for (int i = 0; i < 2; i++) {
                    for (int t = 0; t < 4; t++) {
                        for (int s = 0; s < 2; s++) {
                            Arrays.fill(vis, false);
                            flag = false;
                            pos[0] = l;
                            pos[1] = i;
                            pos[2] = t;
                            pos[3] = s;
                            dfs(0, 0, map);
                            if (flag) return true;
                        }
                    }
                }
            }
            return false;
        }
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int t = sc.nextInt();
            while (t-- > 0) {
                int n = sc.nextInt();
                int[][] g = new int[n][n];
                for (int i = 0; i < n; i++) {
                    for (int j = 0; j < n; j++) {
                        g[i][j] = sc.nextInt();
                    }
                }
    
                boolean ans = solve(g);
                System.out.println(ans ? "Yes" : "No");
            }
        }
    }
    
  • 技巧:通过暴力枚举所有可能的图形排列组合,使用深度优先搜索(DFS)尝试放置每种图形。

第八题:拼十字

  • 赛题:给定N个矩形,每个矩形有长度、宽度和颜色,计算可以拼成十字的矩形对数量。
  • 解题思路:通过排序和树状数组(Fenwick Tree)维护宽度信息,快速统计满足条件的矩形对数量。
  • 代码
    import java.io.*;
    import java.util.*;
    
    public class Main {
        static class FenwickTree {
            int n;
            int[] tree;
    
            public FenwickTree(int n) {
                this.n = n;
                tree = new int[n + 1];
            }
    
            int lowbit(int i) {
                return i & -i;
            }
    
            void add(int i, int val) {
                for (; i <= n; i += lowbit(i)) {
                    tree[i] += val;
                }
            }
    
            int preSum(int i) {
                int ret = 0;
                for (; i > 0; i -= lowbit(i)) {
                    ret += tree[i];
                }
                return ret;
            }
    
            int rangeSum(int l, int r) {
                return preSum(r) - preSum(l - 1);
            }
        }
    
        static int maxn = 100010;
        static int ans = 0;
        static int mod = (int) 1e9 + 7;
    
        public static void main(String[] args) {
            Scanner sc = new Scanner(System.in);
            int n = sc.nextInt();
            List<int[]> arr = new ArrayList<>();
    
            for (int i = 0; i < n; i++) {
                int l = sc.nextInt();
                int w = sc.nextInt();
                int c = sc.nextInt();
                arr.add(new int[]{l, w, c});
            }
    
            arr.sort((o1, o2) -> {
                if (o1[0] != o2[0]) return Integer.compare(o1[0], o2[0]);
                else return Integer.compare(o1[1], o2[1]);
            });
    
            FenwickTree[] tree = new FenwickTree[3];
            for (int i = 0; i < 3; i++) tree[i] = new FenwickTree(maxn);
    
            for (int[] a : arr) {
                int l = a[0];
                int w = a[1];
                int c = a[2];
                for (int i = 0; i < 3; i++) {
                    if (c == i) continue;
                    ans = (ans + tree[i].rangeSum(w + 1, maxn)) % mod;
                }
                tree[c].add(w, 1);
            }
            System.out.println(ans);
        }
    }
    
  • 技巧:通过排序和树状数组维护宽度信息,快速统计满足条件的矩形对数量,避免直接暴力枚举。