P1314 聪明的质监员

传送门

看到最值的问题容易想到二分答案

二分答案已经有一个 log 了

考虑如何O(n) 求出每个区间和

显然前缀和,O(n) 扫一遍然后对每个区间O(1)统计答案

注意long long,然后就过了

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
typedef long long ll;
inline int read()
{
    int x=0,f=1; char ch=getchar();
    while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); }
    while(ch>='0'&&ch<='9') { x=(x<<1)+(x<<3)+(ch^48); ch=getchar(); }
    return x*f;
}
const int N=2e5+7;
int n,m;
int a[N],b[N],l[N],r[N];
ll sum[N],ans,S;
int tot[N];
inline ll check(int mid)
{
    ll res=0;
    for(int i=1;i<=n;i++)
    {
        sum[i]=sum[i-1]; tot[i]=tot[i-1];
        if(a[i]<mid) continue;
        sum[i]+=b[i]; tot[i]++;
    }
    for(int i=1;i<=m;i++) res+=1ll*(tot[r[i]]-tot[l[i]-1])*(sum[r[i]]-sum[l[i]-1]);
    return res;
}
int L,R,mid;
int main()
{
    n=read(); m=read(); scanf("%lld",&S);
    for(int i=1;i<=n;i++) a[i]=read(),b[i]=read();
    for(int i=1;i<=m;i++) l[i]=read(),r[i]=read();
    R=1e6+7; ans=S;
    while(L<=R)
    {
        mid=L+R>>1;
        ll res=check(mid);
        if(res<S) R=mid-1,ans=min(ans,S-res);
        else L=mid+1,ans=min(ans,res-S);
    }
    printf("%lld",ans);
    return 0;
}

 

原文地址:https://www.cnblogs.com/LLTYYC/p/9887377.html