NC 16597 二分 + 前缀和

题意

传送门 NC 16597

题解

Y = ∑ i = 1 m ( ∑ j 1 × ∑ j v j ) , w j ≥ W , L i ≤ j ≤ R i Y=\sum_{i=1}^{m}(\sum_{j}1\times \sum_{j}v_{j}),w_j\geq W,L_i\leq j\leq R_i Y=i=1m(j1×jvj),wjW,LijRi
Y Y Y w w w 递增单调不增,故二分参数 w w w。预处理前缀和,则 Y i Y_i Yi ∑ j 1 \sum_{j}1 j1 ∑ j v j \sum_{j}v_{j} jvj 项可以 O ( 1 ) O(1) O(1) 内求出。考虑到计算 Y Y Y 可能爆 l o n g   l o n g long\ long long long,且 S S S 范围较小,则 Y Y Y 值超出 S × 2 S\times 2 S×2 时即可停止计算,因为此时 Y Y Y 已超过 a b s ( Y − S ) abs(Y-S) abs(YS) 的可能最小值。

#include <bits/stdc++.h>
using namespace std;
#define max(a, b) ((a) > (b) ? (a) : (b))
#define min(a, b) ((a) < (b) ? (a) : (b))
#define maxn 200005
typedef long long ll;
ll n, m, s, limit;
ll w[maxn], v[maxn], l[maxn], r[maxn], num[maxn], sum[maxn];

ll calc(ll x)
{
    for (int i = 1; i <= n; i++)
    {
        num[i] = num[i - 1], sum[i] = sum[i - 1];
        if (w[i] >= x) num[i]++, sum[i] += v[i];
    }
    ll y = 0, s1 = 0, s2 = 0;
    for (int i = 1; i <= m; i++)
    {
        s1 = num[r[i]] - num[l[i] - 1], s2 = sum[r[i]] - sum[l[i]- 1];
        if ((y += s1 * s2) > limit) break;
    }
    return y; 
}

int main()
{
    scanf("%lld%lld%lld", &n, &m, &s);
    for (int i = 1; i <= n; i++) scanf("%lld%lld", w + i, v + i); 
    for (int i = 1; i <= m; i++) scanf("%lld%lld", l + i, r + i);
    limit = s << 1;
    ll lb = 0, ub = 1000005;
    while (ub - lb > 1)
    {
        ll mid = (lb + ub) >> 1;
        if (calc(mid) - s < 0) ub = mid;
        else lb = mid;
    }
    printf("%lld\n", min(abs(calc(lb) - s), abs(calc(ub) - s)));
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值