P9519 pay 题解。
1. 题解
一眼二分答案,然后考虑如何快速判断当前 满足题意。
首先把一个位置左右两边的贡献拆开,这样就不需要考虑绝对值了。
对于左边的贡献,我们从左到右扫一遍,维护一个队列和一个 , 表示当前位置 左边的贡献,队列表示这些贡献的位置。
每次 向后移动, 减去队列长度,并且弹出队列中 的元素。
右边的贡献同理,算完贡献后和 比较即可。
时间复杂度 , 为值域。
2. Code
#include <cstring> #include <iostream> #include <queue> using namespace std; const int N = 1e6 + 5; int n, m, a[N], b[N]; long long l, r = 1e10, c[N], sum, cnt; bool vis[N]; queue<int> Q; bool check(long long k) { memset(c, 0, sizeof(c)); sum = cnt = 0, Q = {}; for (int i = 1; i <= n; i++) { sum -= cnt; if (cnt && k - (i - Q.front()) == 0) Q.pop(), --cnt; if (vis[i]) Q.push(i), ++cnt, sum += k; c[i] += sum; } sum = cnt = 0, Q = {}; for (int i = n; i >= 1; i--) { sum -= cnt; if (cnt && k - (Q.front() - i) == 0) Q.pop(), --cnt; c[i] += sum; if (vis[i]) Q.push(i), ++cnt, sum += k; } for (int i = 1; i <= n; i++) if (c[i] < a[i]) return false; return true; } int main() { ios::sync_with_stdio(false); cin.tie(nullptr); cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i], vis[b[i]] = true; while (l < r) { long long mid = (l + r) >> 1; if (check(mid)) r = mid; else l = mid + 1; } cout << l; return 0; }
cpp