題面c++
不難發現,\(W\)增大時,\(Y\)值會隨之減少。spa
因而考慮二分\(W\)。code
如何\(\mathcal{O}(N)check?\)get
每一次前綴和記錄一下\(1…i\)之間\(w_i \ge W\)的個數及\(v_i\)之和。it
計算出\(|Y_1+Y_2+…+Y_m-S|\),與當前的最小答案取最小值。class
返回\(Y_1+Y_2+…+Y_m > S\)。while
#include <bits/stdc++.h> #define int long long #define itn int #define gI gi using namespace std; inline int gi() { int f = 1, x = 0; char c = getchar(); while (c < '0' || c > '9') {if (c == '-') f = -1; c = getchar();} while (c >= '0' && c <= '9') x = (x << 3) + (x << 1) + (c ^ 48), c = getchar(); return f * x; } const int maxn = 200003; int n, m, s, w[maxn], v[maxn], Y, l[maxn], r[maxn], maxx, sum, ans = 1000000000000007, qw[maxn], qv[maxn]; inline bool check(int x) { memset(qw, 0, sizeof(qw)); memset(qv, 0, sizeof(qv));//初始化 for (int i = 1; i <= n; i+=1) qw[i] = qw[i - 1] + (w[i] >= x), qv[i] = qv[i - 1] + (w[i] >= x) * (v[i]);//前綴和 Y = sum = 0; for (int i = 1; i <= m; i+=1) { Y += (qw[r[i]] - qw[l[i] - 1]) * (qv[r[i]] - qv[l[i] - 1]);//計算Y值的和 } if (Y - s < 0) sum = s - Y; else sum = Y - s; return Y >= s; } signed main() { n = gi(), m = gi(), s = gi(); for (int i = 1; i <= n; i+=1) { w[i] = gi(), v[i] = gi(); maxx = max(maxx, w[i]); } for (int i = 1; i <= m; i+=1) { l[i] = gi(), r[i] = gi(); } int l = 0, r = maxx; while (l <= r) { int mid = (l + r) >> 1; if (check(mid)) l = mid + 1; else r = mid - 1; ans = min(ans, sum);//更新答案 } printf("%lld\n", ans);//輸出 return 0; }