題解【洛谷P1314】[NOIP2011]聰明的質監員

題面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;
}
相關文章
相關標籤/搜索