二分答案 NOIP 2011 聰明的質監員
阿新 • • 發佈:2019-02-17
題意:個礦石,每個礦石都有自己的重量 ,以及價值。接下來會進行以下四個操作:
1.給定個區間;
2.選出一個引數;
3.對於一個區間,計算礦石在這個區間上的檢驗值,是礦石編號。
4.這批礦產的檢驗結果
給定一個,求的最小值。
我們發現,的值越大,的值越小,所以當時,我們需要增大的值,反之亦然。
我們二分的值,對於每個二分到的值,我們根據要求求出和,然後列舉每一個區間,求出的值。最後根據和的值判斷增大還是減小即可。
#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;
}