一开始的想法是二分(|s-y|)的值t,然后根据二分到的值,看是否能够找到一个W,使(s-tle yle s + t),并且答案具有二段性,因为如果对于t能够找到一个W使得满足条件,那么所有比t大的值,都能够满足存在W使得(s-tle yle s + t),所以满足二段性,由于是整数二分,一定能够找到一个最小的t使得(|s - y|=t),但是这样的话,没想到怎么去求W...
思路:二分W,如果W的值使得s - y > 0,为了让|s - y|更小,应该让W小一些,如果W的值使得s - y <= 0,为了让|s - y|更小,应该让W大一些,在二分过程中求出(|s-y|)最小值(和之前做的二分有些区别,不是直接二分答案),另外,因为有区间求和,所以再算s - y的时候要用前缀和优化一下
#include<iostream>
#include<cstring>
using namespace std;
#define LL long long
const int N = 200010;
int n, m;
LL s, ans = 1e12 + 10;
int w[N], v[N], l[N], r[N];
LL a[N], b[N];
LL check(LL W){
memset(a, 0, sizeof a);
memset(b, 0, sizeof b);
for(int i = 1; i <= n; i ++){
if(w[i] >= W) a[i] += a[i - 1] + 1, b[i] += b[i - 1] + v[i];
else a[i] = a[i - 1], b[i] = b[i - 1];
}
LL res = 0;
for(int i = 1; i <= m; i ++)
res += (a[r[i]] - a[l[i] - 1]) * (b[r[i]] - b[l[i] - 1]);
return s - res;
}
int main(){
cin >> n >> m >> s;
for(int i = 1; i <= n; i ++) cin >> w[i] >> v[i];
for(int i = 1; i <= m; i ++) cin >> l[i] >> r[i];
LL ll = 0, rr = 1e6;
while(ll < rr){
LL mid = ll + rr >> 1;
LL val = check(mid);
if(val > 0) rr = mid;
else ll = mid + 1;
ans = min(ans, abs(val));
}
cout << ans << endl;
return 0;
}