题意:
n
n
个矿石,每个矿石都有自己的重量 ,以及价值
vi
v
i
。接下来会进行以下四个操作:
1.给定
m
m
个区间;
2.选出一个参数
W
W
;
3.对于一个区间,计算矿石在这个区间上的检验值
Yi=∑j1∗∑jvj, j∈[li,ri] 并且 wj>=W
Y
i
=
∑
j
1
∗
∑
j
v
j
,
j
∈
[
l
i
,
r
i
]
并
且
w
j
>=
W
,
j
j
是矿石编号。
4.这批矿产的检验结果
给定一个 S S ,求的最小值。
我们发现, W W 的值越大,的值越小,所以当 Y>S Y > S 时,我们需要增大 W W 的值,反之亦然。
我们二分的值,对于每个二分到的 W W 值,我们根据要求求出和 ∑jvj ∑ j v j ,然后枚举每一个区间,求出 Y Y 的值。最后根据和 S S 的值判断增大还是减小即可。
#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;
}