考点
题解
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 48 49 50 51 52 53 54 55 56
| #include <bits/stdc++.h> using namespace std; typedef long long ll; const int maxn = 2e5 + 50; int n, m;
ll s, wv[maxn], vv[maxn];
struct node { int w_, v_; } a[maxn];
struct range { int l_, r_; } b[maxn];
ll calc(int mid) { memset(wv, 0, sizeof(wv)), memset(vv, 0, sizeof(vv)); ll sum = 0; for (int i = 1; i <= n; ++i) { if (a[i].w_ >= mid) { wv[i] += 1, vv[i] += a[i].v_; } wv[i] += wv[i - 1], vv[i] += vv[i - 1]; } for (int i = 1; i <= m; ++i) { sum += (wv[b[i].r_] - wv[b[i].l_ - 1]) * (vv[b[i].r_] - vv[b[i].l_ - 1]); } return sum; }
int main() { cin >> n >> m >> s; int l = 0, r = 0; for (int i = 1; i <= n; ++i) cin >> a[i].w_ >> a[i].v_, r = max(r, a[i].w_); ++r; for (int i = 1; i <= m; ++i) cin >> b[i].l_ >> b[i].r_; ll ans = LLONG_MAX; while (l <= r) { int mid = (l + r) / 2; ll y = calc(mid); ans = min(ans, abs(s - y)); if (y == s) { break; } else if (y > s) { l = mid + 1; } else { r = mid - 1; } } cout << ans; return 0; }
|
思路
根据题意,每个区间内都有:
Y = 合法个数乘上合法价值和
而要我们求的y
就等于每个区间的Y
之和。
显然区间合法个数
与区间合法价值和
是满足容斥原理的,可以使用前缀和进行优化。
由于要让y
尽可能地接近s
,发现结果具有单调性,可以进行答案二分:
- 标准值
W
越大,那么合法的矿石就少,y
就小;
- 标准值
W
越小,那么合法的矿石就多,y
就大;
y
小于s
时,说明y
应该变大,这样才能接近s
,也就是让W
变小;
y
大于s
时,说明y
应该变小,这样才能接近s
,也就是让W
变大。
而W
的二分范围等于[0, 最大矿石重量 + 1]
,
左边界是所有矿石都满足条件时,右边界是所有矿石都不满足条件时;这样就不会遗漏情况。