您的位置:首页 > 其它

[NOIP2011] 聪明的质监员 二分+前缀和

2017-08-05 06:34 323 查看
考试的时候打的二分但没有用前缀和维护。但是有个小细节手误打错了结果挂掉了。

绝对值的话可能会想到三分,但是注意到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
,v
;
struct haha{
long long left,right;
}cun
;
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
,prevv
;
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  二分