聪明的质监员

P1314 [NOIP2011 提高组] 聪明的质监员 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

  • 二分思路
  • 当y>s时需要增大w来减小y
  • 当y<s时需要减小w来增大y
  • 所以y>s or y<s就成为judge函数返回值,用于控制w增大取右边还是减小取左边
  • judge函数内计算y值用前缀和的思想,pre_n代表个数,pre_v代表值,对每个区间用乘法计算
// https://www.luogu.com.cn/problem/P1314
#include <bits/stdc++.h>
using namespace std;
#define ll long long
#define MAX 200005
ll n, m, pre_n[MAX], pre_v[MAX], v[MAX], w[MAX], ans, r[MAX], l[MAX], s, sum = 0x3f3f3f3f3f3f3f3f, max_w = -1, min_w = 2147483647;
void init()
{
    ans = 0;
    memset(pre_n, 0, sizeof(pre_n));
    memset(pre_v, 0, sizeof(pre_v));
}
bool judge(ll ww)
{
    init();
    for (ll i = 1; i <= n; i++)
        if (w[i] >= ww)
            pre_n[i] = pre_n[i - 1] + 1, pre_v[i] = pre_v[i - 1] + v[i];
        else
            pre_n[i] = pre_n[i - 1], pre_v[i] = pre_v[i - 1];
    for (ll i = 1; i <= m; i++)
    {
        ans += (pre_n[r[i]] - pre_n[l[i] - 1]) * (pre_v[r[i]] - pre_v[l[i] - 1]);
    }
    sum = min(sum, llabs(ans - s));
    return ans > s;
}
void input()
{
    cin >> n >> m >> s;
    for (ll i = 1; i <= n; i++)
    {
        scanf("%lld%lld", w + i, v + i);
        max_w = max(w[i], max_w);
        min_w = min(w[i], min_w);
    }
    for (int i = 1; i <= m; i++)
    {
        scanf("%lld%lld", l + i, r + i);
    }
}
int main()
{
    input();
    ll left = min_w - 1, right = max_w + 2;
    while (left <= right)
    {
        ll mid = (left + right) >> 1;
        if (judge(mid))
            left = mid + 1;
        else
            right = mid - 1;
    }
    printf("%lld", sum);
}

 

posted on 2022-08-09 10:44  樵风  阅读(30)  评论(0)    收藏  举报