1. 程式人生 > >[二分]NOIP2011 day2 T2 聰明的質檢員

[二分]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.