1138 聪明的质监员
2011年NOIP全国联赛提高组
第一行包含三个整数 n,m,S,分别表示矿石的个数、区间的个数和标准值。
接下来的 n 行,每行2 个整数,中间用空格隔开,第i+1 行表示i 号矿石的重量wi 和价值vi 。
接下来的 m 行,表示区间,每行2 个整数,中间用空格隔开,第i+n+1 行表示区间[Li,Ri]的两个端点Li 和Ri。注意:不同区间可能重合或相互重叠。
输出只有一行,包含一个整数,表示所求的最小值。
5 3 15
1 5
2 5
3 5
4 5
5 5
1 5
2 4
3 3
10
program df;
var i,j,n,m,mid,max,x,y,l,r:longint;
ans,s,t:int64;
a,b,c,d:array[0..1000000] of longint;
e,f:array[0..1000000] of int64;
function get(x:longint):int64;
var w,z1,z2:int64;
begin
fillchar(e,sizeof(e),0);
fillchar(f,sizeof(f),0);
w:=0;
for i:=1 to n do
if a[i]>=x then
begin
e[i]:=e[i-1]+b[i]; //前缀数组(记录1 到 每个矿石 的价值和)(以x为参数)
f[i]:=f[i-1]+1; //作用同上
end
else
begin
e[i]:=e[i-1];
f[i]:=f[i-1];
end;
for i:=1 to m do
begin
z1:=e[d[i]]-e[c[i]-1]; //求c[i] -d[i]的价值和
z2:=f[d[i]]-f[c[i]-1]; //作用同上
w:=w+z1*z2;
end;
get:=w;
end;
begin
readln(n,m,s);
for i:=1 to n do
readln(a[i],b[i]);
for i:=1 to m do
readln(c[i],d[i]);
max:=-maxlongint;
ans:=maxlongint*10000;
for i:=1 to n do
if a[i]>max then max:=a[i];
l:=0;
r:=max+10; //尽量使更大一些
while l<r do
begin
mid:=(l+r) div 2;
t:=get(mid);
if abs(t-s)<ans then ans:=abs(t-s);
if ans=0 then break; //此时检验值等于标准值,已经为最接近,则退出
if s>t then r:=mid //若检验值小于标准值则往前搜(满足条件的越多,检验值越大,越接近)
else l:=mid+1; //若检验值大于标准值则往后搜(满足条件的越少,检验值越小,越接近)
end;
writeln(ans);
end.