LUOGU P1314 聪明的质监员 (二分答案)

传送门

解题思路

因为要求最小值,并且满足单调性,那么可以想到二分答案。刚开始逗比了,二分答案里又套了个二分,调到死也没调出来。其实只要维护一个前缀和就行了。

#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;
}
View Code
原文地址:https://www.cnblogs.com/sdfzsyq/p/9772726.html