从题中描述可以看出w和检验结果之间有一定关系:w越大检验结果越小,w越小检验结果越大。从而得到w的结果具有一个单调的性质。然后根据这个性质可以考虑二分w的做法。
在二分的过程中,如果Y>S那么w就得增大,如果Y<S那么w就得减小,如果Y==S那么直接退出就可以了。但我们最终的答案是需要取|S-Y|的最小值。
在计算Y的过程中也要注意不能直接暴力模拟,由于w的限制无法在一开始就对价格进行前缀和计算,但在计算Y的函数中w的值是确定的,在这时候可以使用前缀和将时间复杂度降低为:O(N)。
否则会超时。
#include <bits/stdc++.h>
typedef long long ll;

using namespace std;
const int maxn = 200000+10;
ll rock[maxn][2];
ll qujian[maxn][2];
ll n, m, S;

ll jiany(ll mid) {
    //构造价格的前缀和
    ll price[maxn]={}, num[maxn]={}, y=0;
    for (int i=1;i<=n;i++) {
        price[i] = price[i-1];
        num[i] = num[i-1];
        if (rock[i][0]>=mid) {
            price[i] += rock[i][1];
            num[i] += 1;
        }
    }
    //通过前缀和,遍历区间快速求结果
    for (int i=1;i<=m;i++) {
        y += (num[qujian[i][1]]-num[qujian[i][0]-1])*(price[qujian[i][1]]-price[qujian[i][0]-1]);
    }
    return y;
}

int main() {
    scanf("%lld %lld %lld", &n, &m, &S);
    for (int i=1;i<=n;i++) {
        scanf("%lld %lld", &rock[i][0], &rock[i][1]);
    }
    for (int i=1;i<=m;i++) {
        //保存测试的左右区间。
        scanf("%lld %lld", &qujian[i][0], &qujian[i][1]);
    }
    ll l = 0, r = maxn, ans = 1e12;
//     cout<<jiany(4)<<endl;
    while (l<r) {
        ll mid = (l+r)/2;
        ll Y = jiany(mid);
//         cout<<l<<" "<<r<<endl;
//         cout<<"Y="<<Y<<endl;
        if (Y>S) {
            l = mid+1;
            ans = min(ans, abs(S-Y));
        }
        if (Y<S) {
            r = mid;
            ans = min(ans, abs(S-Y));
        }
        if (Y==S) {
            cout<<mid<<endl;
            return 0;
        }
    }
    cout<<ans;
    return 0;
}