1. 程式人生 > >二分答案 NOIP 2011 聰明的質監員

二分答案 NOIP 2011 聰明的質監員

題意:n個礦石,每個礦石都有自己的重量 wi,以及價值vi。接下來會進行以下四個操作:
1.給定m個區間[li,ri]
2.選出一個引數W
3.對於一個區間[li,ri],計算礦石在這個區間上的檢驗值Yi=j1jvjj[li,ri]wj>=Wj是礦石編號。
4.這批礦產的檢驗結果Y=imYi

給定一個S,求|SY|的最小值。

我們發現,W的值越大,Y的值越小,所以當Y>S時,我們需要增大W的值,反之亦然。

我們二分W的值,對於每個二分到的W值,我們根據要求求出j1jvj,然後列舉每一個區間,求出Y的值。最後根據YS的值判斷增大還是減小W即可。

#include<bits/stdc++.h>
#define ll long long
using namespace std;
ll w[202000],v[202000],sum[202000],le,ri,summ,maxx;
ll n,m,s,l[202000],r[202000],cnt[202000],ans=1e+12;
bool check(ll mid)
{
    for(int i=1;i<=n;++i)
    {
        sum[i]=0
; cnt[i]=0; } summ=0; for(ll i=1;i<=n;++i) { if(w[i]>=mid) { sum[i]=sum[i-1]+v[i]; cnt[i]=cnt[i-1]+1; } else { sum[i]=sum[i-1]; cnt[i]=cnt[i-1]; } } for(ll i=1;i<=m;++i) { ll x=sum[r[i]]-sum[l[i]-1
]; ll y=cnt[r[i]]-cnt[l[i]-1]; summ+=x*y; } if(s<summ) return true; return false; } int main() { cin>>n>>m>>s; for(ll i=1;i<=n;++i) { scanf("%lld%lld",&w[i],&v[i]); maxx=max(maxx,w[i]); } le=0,ri=maxx; for(ll i=1;i<=m;++i) scanf("%lld%lld",&l[i],&r[i]); ll mid; while(ri>=le) { mid=(le+ri)/2; if(check(mid)) le=mid+1; else ri=mid-1; if(ans>llabs(s-summ)) ans=llabs(s-summ); } cout<<ans; return 0; }