1. 程式人生 > >『NOIP 2011』聰明的質監員(二分答案 + 前綴和)

『NOIP 2011』聰明的質監員(二分答案 + 前綴和)

可能 can 表示 代碼 標準 和數 怎麽 abs load

題目鏈接

題目描述

小T 是一名質量監督員,最近負責檢驗一批礦產的質量。這批礦產共有 \(n\) 個礦石,從 \(1\)\(n\) 逐一編號,每個礦石都有自己的重量 \(w_i\) 以及價值 \(v_i\) 。檢驗礦產的流程是:

1 、給定m個區間\([L_i,R_i]\)

2 、選出一個參數\(W\)

3 、對於一個區間\([L_i,R_i]\),計算礦石在這個區間上的檢驗值\(Y_i\)

技術分享圖片

這批礦產的檢驗結果 \(Y\) 為各個區間的檢驗值之和。即:\(Y_1+Y_2...+Y_m\)

若這批礦產的檢驗結果與所給標準值 \(S\) 相差太多,就需要再去檢驗另一批礦產。小T不想費時間去檢驗另一批礦產,所以他想通過調整參數 \(W\)

的值,讓檢驗結果盡可能的靠近標準值\(S\),即使得\(S-Y\)的絕對值最小。請你幫忙求出這個最小值。



解題思路

題目要求參數 \(W\) 最小,我們可以考慮二分 \(W\) 的值。

二分後我們就要考慮怎麽檢驗是否合法了。

因為 \(m\) 的最大值是 \(2e5\) 所以我們不可能暴力枚舉每個區間。每個區間必須在 \(O(1)\) 的時間內處理出來。我們發現這個式子的含義就是區間內 \(w\) 大於等於 \(W\) 的礦石的個數稱這些礦石的價值之和。

顯然,我們可以在\(O(n)\)的復雜度內處理出來兩個前綴和數組,一個表示個數,一個表示和。每個區間的查詢的復雜度就被降低到了\(O(1)\)

,這樣我們的總復雜度就是\(O(log_{玄學} \times (m+n))\)

腦子抽了,一開始還想著三分。。。。



代碼

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#define ll long long
using namespace std;
const int maxn=2000050;
ll n,m,s;
ll w[maxn],v[maxn],pre[maxn],prew[maxn];
int l[maxn],r[maxn];
inline ll check(ll x){
    for(register int i=1;i<=n;i++){
        pre[i]=prew[i]=0;
        if(w[i]>=x){
            pre[i]=1;
            prew[i]=v[i];
        }
        pre[i]+=pre[i-1];
        prew[i]+=prew[i-1];
    }
    ll ans=0;
    for(register int i=1;i<=m;i++){
        ll sum=pre[r[i]]-pre[l[i]-1];
        ll tot=prew[r[i]]-prew[l[i]-1];
        //cout<<pre[r[i]]<<' '<<pre[l[i]-1]<<' '<<prew[r[i]]<<' '<<prew[l[i]-1]<<endl;
        ans+=sum*tot;
    }
    return ans;
}
int main(){
    scanf("%lld%lld%lld",&n,&m,&s);
    ll ma=0;
    for(register int i=1;i<=n;i++){
        scanf("%lld%lld",&w[i],&v[i]);
        ma=max(ma,w[i]);
    }
    for(register int i=1;i<=m;i++){
        scanf("%d%d",&l[i],&r[i]);
    }
    register ll l=0,r=999999999999999,ans=999999999999999;
    while(l<=r){
        register ll mid=(l+r)>>1;
        ll tmp=check(mid);
        //cout<<l<<' '<<r<<' '<<tmp<<endl;
        if(tmp>s){
            l=mid+1;
        }
        else r=mid-1;
        ans=min(ans,abs(tmp-s));
    }
    cout<<ans<<endl;
}

『NOIP 2011』聰明的質監員(二分答案 + 前綴和)