Luogu P1314 [NOIP2011 提高組] 聰明的質監員
阿新 • • 發佈:2021-11-11
題意
題目描述
- 給定\(n\)個物品,給定每個物品的 重量 \(w_i\) 和 價值 \(v_i\)
- 給定一個標準值 \(s\) 以及一個引數 \(w\)
- 質檢員每次會抽取\(m\)個區間,每次的抽檢結果為 \(y = \sum_{l_i}^{r_i} (w_i \ge w) · \sum_{l_i}^{r_i} v_i\)
- 求出 \(\min{\mid{y - s}\mid}\)
資料範圍
\(1 \le n,m \le 2^5\), \(0 < w_i, v_i \le 10^6\) \(0 < s \le 10^12\), \(1 \le l_i \le r_i \le n\)
SOLUTION
當 \(y > s\) 的時候, \(y - s > 0\) 當 \(y < s\) 的時候, \(y - s < 0\) 我們想讓 \(y\) 儘可能的逼近 \(s\) 對於引數\(w\),當\(w\)越大,\(y\)越小
因此本題具有單調性。 考慮二分\(w\) 使得 \(y\) 儘可能的逼近\(s\) 即可
AC_CODE
#include <bits/stdc++.h> #define LL long long using namespace std; const int N = 2e5 + 10; int n, m, l = INF, r = -INF; LL s; // 不開 long long 見祖宗 | =^_^= | int L[N], R[N]; int w[N], v[N]; LL p1[N], p2[N]; LL chk(int x) { for(int i = 1; i <= n; i ++ ) { p1[i] = p1[i - 1]; p2[i] = p2[i - 1]; if(w[i] >= x) { p1[i] += v[i]; p2[i] ++; } } // printf("\n%d\n", x); LL ANS = 0; rep(i, 1, m) { // printf("> %d %d %lld %lld\n",L[i], R[i], (p1[R[i]] - p1[L[i] - 1]) , (p2[R[i]] - p2[L[i] - 1])); ANS += (p1[R[i]] - p1[L[i] - 1]) * (p2[R[i]] - p2[L[i] - 1]); } return ANS; } inline void solve() { read(n); read(m); read(s); rep(i, 1, n) { read(w[i]); read(v[i]); l = min(l, w[i]); r = max(r, w[i]); } rep(i, 1, m) { read(L[i]); read(R[i]); } l --, r ++; LL ans = INFF; while(l <= r) { // 由於 l = mid + 1, r = mid - 1 因此while迴圈裡面的條件應該是 l <= r int mid = l + r >> 1; LL res = chk(mid); if(res >= s) l = mid + 1; // 如果結果 y > s 我們就讓 w 大一點 這樣 y就會小一點更逼近 s else r = mid - 1; //同理 ans = min(ans, abs(res - s)); // printf("> %d %lld\n", mid, res); } printf("%lld\n", ans); } signed main() { // freopen("in.txt", "r", stdin); solve(); return 0; }