题解 P1314 【聪明的质监员】
AtlasDelRey · · 题解
二分答案就可以了。二分所取的w,这里记作ww,记录w[]中min和max,在[min-1,max+1]这个区间二分(一个都不合法或者全部合法),在check()中扫一遍w[],用前缀和记录合法个数(sum[][0])和价值和(sum[][1]),(sum[r[i]][0]-sum[l[i]-1][0])*(sum[r[i]][1]-sum[l[i]-1][1])就是此时的Yi,这里记作summ,如果summ>s说明ww过小,summ<0说明ww过大。
···cpp
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
using namespace std;
long long ans=1e18,n,m,s,w[200002],v[200002],maxx,minn=1e9,l[200002],r[200002],sum[200002][2];
long long abss(long long a)
{
return a>0?a:(-a);
}
void check(long long ll,long long rr)
{
long long ww=(ll+rr)/2,summ=0;
memset(sum,0,sizeof(sum));
for(int i=1;i<=n;i++)
{
if(w[i]>=ww)sum[i][0]=sum[i-1][0]+1,sum[i][1]=sum[i-1][1]+v[i];
else sum[i][0]=sum[i-1][0],sum[i][1]=sum[i-1][1];
}
for(int i=1;i<=m;i++)
{
summ+=(sum[r[i]][0]-sum[l[i]-1][0])*(sum[r[i]][1]-sum[l[i]-1][1]);
}
ans=min(abss(summ-s),ans);
if(ll>=rr)return;
if(summ==s){
ans=0;
return;
}
// if(ll==ww)return;
if(summ>s)check(ww+1,rr);
else check(ll,ww-1);
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=1;i<=n;i++)
{
scanf("%lld%lld",&w[i],&v[i]);
maxx=max(w[i],maxx);
minn=min(w[i],minn);
}
for(int i=1;i<=m;i++)
scanf("%lld%lld",&l[i],&r[i]);
check(minn-1,maxx+1);
cout<<ans;
}
···