1 条题解
-
0
#5468. 「eJOI2025」度假 题解
问题分析
有 个区间 ,每个区间可以平移 变成 ,要求 ,求所有区间交的最大长度。
关键观察
-
问题转化:设最终所有区间交为 ,则第 个区间需要移动的最小距离为:
- 如果 完全在 左边:需要
- 如果 完全在 右边:需要
- 如果相交:需要移动距离为
-
二分答案:可以二分最终的交集长度 ,检查是否存在 使得总移动距离
算法思路
1. 二分交集长度
设最终交集为 ,对每个区间 :
- 如果 ,需要移动
- 如果 ,需要移动
- 否则不需要移动
2. 检查可行性
对于固定的 ,需要找到 使得总移动距离最小。可以证明代价函数是凸的,可以用三分法找最小值。
3. 优化计算
对于固定的 ,总代价为:
$$\sum \max(0, x - R_i) + \sum \max(0, L_i - (x+len)) $$这可以通过排序后使用前缀和快速计算。
代码实现
#include <vector> #include <algorithm> #include <iostream> using namespace std; typedef long long ll; bool check(int len, int N, vector<int>& L, vector<int>& R, ll K) { // 预处理排序 vector<int> sorted_L = L, sorted_R = R; sort(sorted_L.begin(), sorted_L.end()); sort(sorted_R.begin(), sorted_R.end()); // 计算前缀和 vector<ll> prefix_L(N+1), prefix_R(N+1); for (int i = 0; i < N; i++) { prefix_L[i+1] = prefix_L[i] + sorted_L[i]; prefix_R[i+1] = prefix_R[i] + sorted_R[i]; } // 三分法找最小代价 auto calc_cost = [&](ll x) { // 计算 R_i < x 的部分 int idx1 = lower_bound(sorted_R.begin(), sorted_R.end(), x) - sorted_R.begin(); ll cost1 = x * idx1 - prefix_R[idx1]; // 计算 L_i > x+len 的部分 ll right_bound = x + len; int idx2 = upper_bound(sorted_L.begin(), sorted_L.end(), right_bound) - sorted_L.begin(); ll cost2 = (prefix_L[N] - prefix_L[idx2]) - right_bound * (N - idx2); return cost1 + cost2; }; // 三分搜索范围 ll left = 1, right = 1e18; // 扩大搜索范围 while (right - left > 3) { ll mid1 = left + (right - left) / 3; ll mid2 = right - (right - left) / 3; ll cost1 = calc_cost(mid1); ll cost2 = calc_cost(mid2); if (cost1 <= K || cost2 <= K) return true; if (cost1 < cost2) right = mid2 - 1; else left = mid1 + 1; } // 检查剩余点 for (ll x = left; x <= right; x++) { if (calc_cost(x) <= K) return true; } return false; } int plan_vacation(int N, vector<int> L, vector<int> R, ll K) { // 特判:如果K=0,直接计算原始区间的最大交集 if (K == 0) { int maxL = *max_element(L.begin(), L.end()); int minR = *min_element(R.begin(), R.end()); return max(0, minR - maxL + 1); } // 二分答案:交集长度 int left = 0, right = 1e9, ans = 0; while (left <= right) { int mid = (left + right) / 2; if (check(mid, N, L, R, K)) { ans = mid; left = mid + 1; } else { right = mid - 1; } } return ans; }复杂度分析
- 二分答案: 次
- 可行性检查: 排序预处理,三分 次,每次 二分
- 总复杂度:,在 时可接受
样例验证
样例
N=3, L={1,5,2}, R={3,9,5}, K=3 二分过程: len=0: 可行(代价0) len=1: 可行(代价最小为1) len=2: 可行(代价最小为3) len=3: 不可行(代价最小>3) 返回结果:2优化点
- 预处理排序:避免每次检查重复排序
- 前缀和:快速计算区间和
- 三分法:利用凸性快速找到最小值
- 边界处理:注意整数范围和边界情况
总结
本题通过二分答案+三分搜索,将复杂的最优化问题转化为可行性检查问题。利用区间的有序性和前缀和优化,在合理时间内解决了大规模数据的最优安排问题。
-
- 1
信息
- ID
- 5300
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者