[NOIP2011] 聰明的質監員 二分+字首和
阿新 • • 發佈:2019-02-14
考試的時候打的二分但沒有用字首和維護。但是有個小細節手誤打錯了結果掛掉了。
絕對值的話可能會想到三分,但是注意到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; }