【蓝桥杯真题】2026/4/7【前缀和】


需要注意的点:
1.步数的意思是什么
2.起点从0开始
3.矿洞矿的数量可以不一样
利用前缀和+二分
import java.util.*;
public class Main {
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[] nums = new int[n];
//用来存每个矿洞里有多少个矿,比如 输入 -3 -3 则代表-3矿洞有两个矿,用于计算出前缀和
HashMap<Integer, Integer> map = new HashMap<>();
//这一步开始预处理map,保存每个矿洞有多少个矿
for (int i = 0; i < n; i++) {
nums[i] = sc.nextInt();
map.put(nums[i], map.getOrDefault(nums[i], 0) + 1);
}
//排序,因为题意表示是从0开始可以走m步
Arrays.sort(nums);
// 去重,保证计算前缀和时,不会重复添加矿石
List<Integer> list = new ArrayList<>();
for (int i = 0; i < nums.length; i++) {
if (i == 0 || nums[i] != nums[i - 1]) {
list.add(nums[i]);
}
}
// 强制添加0,保证起点存在(解决无0崩溃)
if (!list.contains(0)) {
list.add(0);
Collections.sort(list); // 重新排序
}
int size = list.size();
long[] pre = new long[size + 1];
//pos0表示0所在数组的位置
int pos0 = -1;
for (int i = 0; i < size; i++) {
//pre[i]代表第i个数,pre[1]计算的就是一个数的前缀和nums[0]
pre[i + 1] = pre[i] + map.getOrDefault(list.get(i), 0);
if (list.get(i) == 0) pos0 = i;
}
long maxAns = 0;
// 1. 只向右走,注意步数到底是什么,比如list.get(2)=3,意味着要走三步
for (int i = pos0; i < size; i++) {
if (list.get(i) > m) break;
maxAns = Math.max(maxAns, pre[i + 1] - pre[pos0]);
}
// 2. 只向左走,注意步数到底是什么,比如list.get(2)=-4,意味着要走四步
for (int i = pos0; i >= 0; i--) {
if (Math.abs(list.get(i)) > m) break;
maxAns = Math.max(maxAns, pre[pos0 + 1] - pre[i]);
}
// 3. 先左 → 折返 → 右(修复二分边界)
for (int i = 0; i < pos0; i++) {
int cost = 2 * Math.abs(list.get(i));
if (cost > m) continue;
int remain = m - cost;
int l = pos0, r = size - 1, right = pos0;
while (l <= r) {
int mid = (l + r) / 2;
if (list.get(mid) <= remain) {
right = mid;
l = mid + 1;
} else r = mid - 1;
}
maxAns = Math.max(maxAns, pre[right + 1] - pre[i]);
}
// 4. 先右 → 折返 → 左
for (int i = pos0 + 1; i < size; i++) {
int cost = 2 * list.get(i);
if (cost > m) break;
int remain = m - cost;
int l = 0, r = pos0, left = pos0;
while (l <= r) {
int mid = (l + r) / 2;
// 修复:这里之前逻辑颠倒,现在精准找最远左边界
if (Math.abs(list.get(mid)) <= remain) {
left = mid;
r = mid - 1;
} else {
l = mid + 1;
}
}
maxAns = Math.max(maxAns, pre[i + 1] - pre[left]);
}
System.out.println(maxAns);
}
}

浙公网安备 33010602011771号