Description
给定正整数 n 和长度为 n 的序列 xi,yi,保证 xi 单调递增。你要构造 m 个区间 [Li,Ri](m 由你指定),使每个 xi 恰好被 yi 个区间包含。
最大化 mini=1m{Ri−Li},并求该值。无穷输出 −1。
n≤2×105,1≤xi,yi≤109。
Solution
考虑贪心。
假设当前已经满足了 1∼i−1 的限制,维护一个队列表示当前还没确定右端点的所有左端点。
如果 yi=yi−1,那么只要让原来右端点接在 xi−1 的区间接到 xi 即可。
如果 yi>yi−1,这说明原来的区间就算全部接到 xi 上还不够,需要再加 yi−yi−1 个左端点为 xi−1+1 的区间。
如果 yi<yi−1,说明要删掉 yi−1−yi 个区间,由于要让最小值最大,所以需要删掉左端点最小的区间。
于是只要维护一个左端点递增的区间即可,由于区间数很多,顺便记一个这个左端点的个数即可。
时间复杂度:O(n)。
Code
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| #include <bits/stdc++.h>
#define int int64_t
const int kMaxN = 2e5 + 5;
int n; int x[kMaxN], y[kMaxN]; std::pair<int, int> q[kMaxN];
void dickdreamer() { std::cin >> n; for (int i = 1; i <= n; ++i) std::cin >> x[i]; for (int i = 1; i <= n; ++i) std::cin >> y[i]; x[0] = -1e18; int h = 1, t = 0, ans = 1e18; for (int i = 1; i <= n; ++i) { if (y[i] > y[i - 1]) { q[++t] = {x[i - 1] + 1, y[i] - y[i - 1]}; } else if (y[i] < y[i - 1]) { int d = y[i - 1] - y[i]; for (; d && h <= t;) { int w = std::min(q[h].second, d); d -= w, q[h].second -= w; ans = std::min(ans, x[i] - 1 - q[h].first); if (!q[h].second) ++h; else break; } } } std::cout << (ans == 1e18 ? -1 : ans) << '\n'; }
int32_t main() { #ifdef ORZXKR freopen("in.txt", "r", stdin); freopen("out.txt", "w", stdout); #endif std::ios::sync_with_stdio(0), std::cin.tie(0), std::cout.tie(0); int T = 1; while (T--) dickdreamer(); return 0; }
|