[二分]NOIP2011 day2 T2 聪明的质检员

聪明的质检员
From 西部314
背景 Background
NOIP2011 day2 第二题
描述 Description
小T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 n 个矿石,从 1到n 逐一编号,每个矿石都有自己的重量 wi 以及价值vi 。检验矿产的流程是: 
1 、给定m 个区间[Li ,Ri]; 
2 、选出一个参数 W; 
3 、对于一个区间[Li ,Ri],计算矿石在这个区间上的检验值Yi:
Yi=Σ1*Σvj,Σ的循环变量为j,这里j要满足j∈[Li,Ri]且wj≥W,这里j是矿石编号。

这批矿产的检验结果Y为各个区间的检验值之和。ΣYi,Σ的循环变量为i,1≤i≤m。

若这批矿产的检验结果与所给标准值S 相差太多,就需要再去检验另一批矿产。小T不想费时间去检验另一批矿产,所以他想通过调整参数W 的值,让检验结果尽可能的靠近标准值S,即使得S-Y 的绝对值最小。请你帮忙求出这个最小值。 
输入格式 Input Format
第一行包含三个整数n ,m,S,分别表示矿石的个数、区间的个数和标准值。 接下来的n 行,每行 2 个整数,中间用空格隔开,第i+1 行表示 i 号矿石的重量 wi 和价值vi 。 
接下来的m 行,表示区间,每行2 个整数,中间用空格隔开,第i+n+1 行表示区间[Li, Ri]的两个端点 Li 和Ri 。注意:不同区间可能重合或相互重叠。 
输出格式 Output Format
输出只有一行,包含一个整数,表示所求的最小值。 
样例输入 Sample Input [ 复制数据]
样例输出 Sample Output [ 复制数据]
时间限制 Time Limitation
各个测试点1s
注释 Hint
对于10% 的数据,有 1 ≤n ,m≤10; 
对于30% 的数据,有 1 ≤n ,m≤500 ; 
对于50% 的数据,有 1 ≤n ,m≤5,000; 
对于70% 的数据,有 1 ≤n ,m≤10,000 ; 

对于100%的数据,有 1 ≤n ,m≤200,000,0 < wi, vi≤10^6,0 < S≤10^12,1 ≤Li ≤Ri ≤n 。



w为参数

tt[i]表示 1..i个矿中wi>=w的个数  tt[i]=tt[i-1]+1 (满足wi>=w)

                                          else tt[i]=tt[i-1]

vvw[i] 表示1..i个矿中wi>=w的价值和 ww[i]=ww[i-1]+w[i] (满足)

                                                       else ww[i]=ww[i-1]

对于一个l[i] r[i]的查询 mark=(tt[r[i]]-tt[l[i]-1])*(ww[r[i]]-ww[l[i]-1])

累加mark 作为 每一个w 答案

显然 mark单调递减

二分w即可 

二分可以有很多种写法...


    left:=1;right:=max;
    while left+1<right do
    begin
        mid:=(left+right)div 2;
        ans:=work(mid);
        if ans>s then left:=mid
        else right:=mid;
    end;    



procedure search;
var l,r,mid:longint;
    tt,kk:qword;
begin
l:=0;r:=max;ans:=10000000000000;
while l<=r do
  begin
     mid:=(l+r)shr 1;
     tt:=ac(mid);
     if tt>s then kk:=tt-s else kk:=s-tt;
     if ans>kk then ans:=kk;
     if tt<s then r:=mid-1;
     if tt>s then l:=mid+1;
     if tt=s then exit;
  end;
end;

var a,b,n,m,s,ans,left,right,mid,max:int64;
    w,l,r,v,tt,vv:array[0..200000]of int64;
    i,j:longint;

function min(a,b:int64):int64;
begin
    if a>b then exit(b) else exit(a);
end;

function work(ww:int64):int64;
var tot:int64;
    j:longint;
begin
    tot:=0;
    fillchar(tt,sizeof(tt),0);
    fillchar(vv,sizeof(vv),0);
    for j:=1 to n do
        if w[j]>=ww then
        begin
           tt[j]:=tt[j-1]+1;
           vv[j]:=vv[j-1]+v[j];
        end else
        begin
            tt[j]:=tt[j-1];
            vv[j]:=vv[j-1];
        end;
    for j:=1 to m do
    tot:=tot+(tt[r[j]]-tt[l[j]-1])*(vv[r[j]]-vv[l[j]-1]);
    exit(tot);
end;


begin
    readln(n,m,s);
    for i:=1 to n do readln(w[i],v[i]);
    for i:=1 to m do readln(l[i],r[i]);
    max:=0;
    for i:=1 to n do if max<w[i] then max:=w[i];
    left:=1;right:=max;
    while left+1<right do
    begin
        mid:=(left+right)div 2;
        ans:=work(mid);
        if ans>s then left:=mid
        else right:=mid;
    end;
    writeln(min(abs(work(right)-s),abs(work(left)-s)));
    readln;
end.



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值