考试的时候打的二分但没有用前缀和维护。但是有个小细节手误打错了结果挂掉了。
绝对值的话可能会想到三分,但是注意到w增大的时候y是减小的,所以单调性很明显,用二分就可以。但注意一个问题,就是二分最后的结果不一定是最优的,只是在它属于的符号里是最优的,所以需要最后存正负的最优解去比较。
至于check(),先把所有满足wi>=W的所有条件的num(个数)和v(权值)在本位置加上,求前缀和。
即∑vi(wi>=W);∑num(wi>=W)。最后用区间的话用前缀和相减维护即可。
#include<iostream> #include<cstdio> #include<cstring> using namespace std; #define pos(i,a,b) for(long long i=(a);i<=(b);i++) #define N 410000 long long n,m,s; long long w[N],v[N]; struct haha{ long long left,right; }cun[N]; long long ma; long long l,r,ans; long long aabs(long long x){ return x<0?(-x):x; } long long temp,ans1=0x7fffffffffffffffLL,ans2=0x7fffffffffffffffLL; long long pren[N],prevv[N]; long long check(long long x){ temp=0; pos(i,1,n){ pren[i]=pren[i-1]+(w[i]>=x); if(w[i]>=x){ prevv[i]=prevv[i-1]+v[i]; } else{ prevv[i]=prevv[i-1]; } } pos(i,1,m){ temp+=(pren[cun[i].right]-pren[cun[i].left-1])*(prevv[cun[i].right]-prevv[cun[i].left-1]); } if(temp-s>0){ ans1=ans1>temp-s?temp-s:ans1; return 1; } if(temp-s==0){ printf("0"); return 2; } if(temp-s<0){ ans2=ans2>s-temp?s-temp:ans2; return 0; } } int main(){ //freopen("qc.in","r",stdin); //freopen("qc.out","w",stdout); scanf("%lld%lld%lld",&n,&m,&s); pos(i,1,n){ scanf("%lld%lld",&w[i],&v[i]); ma=max(w[i],ma); } pos(i,1,m){ scanf("%lld%lld",&cun[i].left,&cun[i].right); } l=0,r=ma; while(l<=r){ long long mid=(l+r)>>1; //cout<<"mid="<<mid<<" l="<<l<<" r="<<r<<endl;system("pause"); long long qian=check(mid); if(qian==1) l=mid+1; if(qian==2) return 0; if(qian==0) r=mid-1; } long long ans=ans1>ans2?ans2:ans1; cout<<ans; return 0; }