题解 P1314 【聪明的质监员】
聪明的质监员
Solution
二分一个
- 如果
Y>S , 说明如果W 再大些,Y-S 的值可能会更小; - 如果
S>Y , 说明如果W 再小些,S-Y 的值可能会更小.
根据这来调整
Code
#include<cstdio>
#define inf 999999999999//inf值要设的足够大
#define N 200005
#define int long long//后面所有的int都其实是long long
int ans;
int n,m,s;
int aaaa[N];
int sigma[N];
int v[N],w[N];
int le[N],ri[N];
inline int abs(int s){
return s>0?s:-s;
}
inline int min(int a,int b){
return a<b?a:b;
}
bool check(int W){
sigma[0]=0;//sigma为满足w_j>W的w_j的前缀和
aaaa[0]=0;//aaaa为满足w_j>W的数量的前缀和, 分别对应题目中两个sigma
int an=0;//二分的W所对应的答案
for(int i=1;i<=n;++i){
sigma[i]=sigma[i-1];
aaaa[i]=aaaa[i-1];
if(w[i]>=W)sigma[i]+=v[i],++aaaa[i];//维护前缀和
}
for(int i=1;i<=m;++i)
an+=(sigma[ri[i]]-sigma[le[i]-1])*(aaaa[ri[i]]-aaaa[le[i]-1]);//这是一段区间对于答案的贡献
an=an-s;
ans=min(abs(an),ans);
return an>0;//如果答案>S说明答案在小一点(W变大)可能其减去S的绝对值更小
}
main(){
ans=inf;//一开始给ans设一个较大的初值
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",&le[i],&ri[i]);
int l=0ll,r=inf,mid;//看到题解中有人用1-s作为二分范围, 需要足够大
while(l<=r){//l<=r要格外注意
mid=(l+r)>>1;
if(check(mid))l=mid+1ll;
else r=mid-1;
}
printf("%lld",ans);
return 0;
}