【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); } }
- 技巧:通过排序和树状数组维护宽度信息,快速统计满足条件的矩形对数量,避免直接暴力枚举。