题解 P1314 【聪明的质监员】

· · 题解

这题反复做了好久才做出来,自以为还算有些心痛的见解(都是血的代价啊)

垃圾的我准备发表第一篇题解,不喜勿喷

主要是二分求解,在0到最大重量间二分答案,如果和标准的差==0就可以直接退出了

还有就是一个前缀和处理Y中的前面那个项 和后面那个项,对于每一次二分的答案都要处理一遍,

然后用jia()求和得出,比较后进行下一次操作

#include<iostream>
#include<cstdio>
#include<cmath>
#include<cstring>
#define LL long long
using namespace std;
inline LL read()
{
    LL kk=0,f=1;
    char cc=getchar();
    while('9'<cc||cc<'0')
    {
        if(cc=='-')f=-1;
        cc=getchar();
    }
    while('0'<=cc&&cc<='9')
    {
        kk=(kk<<1)+(kk<<3)+cc-'0';
        cc=getchar();
    }
    return kk*f;
}
LL start=0,tail,w[200002],v[200002],qu[200002][2],N,M,S;
LL sum[200002],sumv[200002];
LL myabs(LL a)//一定要自己写,因为cmath里的不支持 long long
{
    if(a<0)return -a;
    else return a;
}
LL mymax(LL a,LL b)
{
    if(a>b)return a;
    else return b;
} 
void work(LL mid)//单次处理每一个s 得到每一组y考虑其Y的值将其中y1,y2...用jia()加起来 
{
    sum[0]=0;sumv[0]=0; 
    for(int i=1;i<=N;++i)
    { 
            if(w[i]>=mid)
            {
                sum[i]=sum[i-1]+1;
                sumv[i]=sumv[i-1]+v[i];
            }
            else 
            {
                sum[i]=sum[i-1];
                sumv[i]=sumv[i-1];
            }
    }
}
LL jia(LL mid)
{
    LL jie=0;
    for(register int i=1;i<=M;++i)
    {
        jie+=(sum[qu[i][1]]-sum[qu[i][0]-1])*(sumv[qu[i][1]]-sumv[qu[i][0]-1]);//-1很重要,丫的检查了好久才检查出来 表示qu【i】【0】也入选 
    }
    return jie;
}
int main()
{
    N=read(),M=read(),S=read();
    for(register int i=1;i<=N;++i)
    {
        w[i]=read();v[i]=read();tail=mymax(tail,w[i]);
    }
    for(register int i=1;i<=M;++i)
    {
        qu[i][0]=read();qu[i][1]=read();//用qu[i][0]表示左,qu【i】【1】表示右
    }
    LL ans=9223372036854775807;
    while(start<=tail)
    {
        LL mid=(start+tail)/2;
        work(mid);
        LL s1=jia(mid);
        if(myabs(s1-S)<ans)ans=myabs(s1-S);
        if(ans==0)goto end;
        if(s1>S)start=mid+1;//如果选取的mid 使s1 过大则提高mid来降低s1 
        else tail=mid-1;
    }
    end:
        printf("%lld",ans);
        return 0;
}