LUOGU P1314 聪明的质监员 (二分答案)
解题思路
因为要求最小值,并且满足单调性,那么可以想到二分答案。刚开始逗比了,二分答案里又套了个二分,调到死也没调出来。其实只要维护一个前缀和就行了。
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<set> using namespace std; const int MAXN = 200005; const int inf = 0x3f3f3f3f; typedef long long LL; inline int rd(){ int x=0,f=1;char ch=getchar(); while(!isdigit(ch)) {f=ch=='-'?0:1;ch=getchar();} while(isdigit(ch)) {x=(x<<1)+(x<<3)+ch-'0';ch=getchar();} return f?x:-x; } int n,m,tmp[MAXN]; LL S,sum[MAXN],ans=1e18; struct Data{ int w,v,id; }data[MAXN]; struct Query{ int l,r; }q[MAXN]; bool check(int Mid){ LL ret=0; for(int i=1;i<=n;i++) { if(data[i].w>=Mid) sum[i]=sum[i-1]+data[i].v,tmp[i]=tmp[i-1]+1; else sum[i]=sum[i-1],tmp[i]=tmp[i-1]; } for(int i=1;i<=m;i++) ret+=(LL)(sum[q[i].r]-sum[q[i].l-1])*(tmp[q[i].r]-tmp[q[i].l-1]); ans=min(ans,abs(ret-S)); return ret>=S?0:1; } int main(){ n=rd(),m=rd();scanf("%lld",&S); for(int i=1;i<=n;i++) data[i].w=rd(),data[i].v=rd(),data[i].id=i; for(int i=1;i<=m;i++) q[i].l=rd(),q[i].r=rd(); int L=1,R=1e6,mid; // cout<<ans; while(L<=R){ mid=(L+R)>>1; if(check(mid)) R=mid-1; else L=mid+1; }cout<<ans; return 0; }