题解 P1314 【聪明的质监员】
二分题~
二分w的值,与所给标准值s对比,[注意这里与其他的二分不一样~] 如果大,就将右边标记j改为此时的w值-1;如果小,就将左边标记i改为w+1,保证区间每次都更贴近标准值。注意同时要更新答案tot值~
另外,如果每次都循环求值会超时,可以预处理出前缀和~
这道题的数据范围较大,答案用long long型~这道题里面哪些用long long型,哪些用int型要区分清楚~
具体的看代码~
#include<cstdio>
#include<cstring>
#define ll long long
int w[200006],n,m;
int x[200006],y[200006],a[200006];
ll k,tot=12425374554373ll,mx,mi=0xfffffff,s[200006],v[200006]; //long long型
ll lmin(ll u,ll v)
{
return u<v ? u:v;
}
int min(int u,int v)
{
return u<v ? u:v;
}
int max(int u,int v)
{
return u>v ? u:v;
}
ll doo(int u)
{
ll ans=0;
memset(a,0,sizeof(a));
memset(s,0,sizeof(s));
for(int i=1;i<=n;i++) //预处理
{
if(w[i]>=u) a[i]=a[i-1]+1,s[i]=s[i-1]+v[i]; //传说中的前缀和~
else a[i]=a[i-1],s[i]=s[i-1];
}
for(int i=1;i<=m;i++) ans+=(a[y[i]]-a[x[i]-1])*(s[y[i]]-s[x[i]-1]);
return ans;
}
int main()
{
scanf("%d%d%lld",&n,&m,&k);
for(int i=1;i<=n;i++)
{
scanf("%d%d",&w[i],&v[i]);
mx=max(w[i],mx);mi=min(w[i],mi);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&x[i],&y[i]);
}
int i=mi,j=mx;
while(i<=j)
{
int mid=(i+j)/2;
ll zz=doo(mid);
if(zz>k)
{
i=mid+1;tot=lmin(tot,zz-k); //这里i和j的顺序与一般的二分不同,要反过来
}
else if(zz<k)
{
j=mid-1;tot=lmin(tot,k-zz);
}
else
{
tot=0;break;
}
}
printf("%lld",tot);
return 0;
}