题意
n
n
个矿石,每个矿石有 两个参数,分别代表它的质量和价值,给定
m
m
个区间 和一个标准值
S
S
,现在选取一个参数 ,求
min{|S−∑i=1m∑j1∑jvj(j∈[Li,Ri],wj≥W)|}
min
{
|
S
−
∑
i
=
1
m
∑
j
1
∑
j
v
j
(
j
∈
[
L
i
,
R
i
]
,
w
j
≥
W
)
|
}
1≤200000≤n,m
1
≤
200000
≤
n
,
m
思路
说白了就是取一个
W
W
, 使 个区间中各自质量不比
W
W
小的矿石价值乘上这个区间满足数,使总贡献与 最接近。
不难发现,
W
W
越小,总贡献越大,那么可以二分 ,求出一个最大的
W
W
使得总贡献小于等于 ,再在这个值附近找答案即可。
代码
#include<bits/stdc++.h>
#define FOR(i,x,y) for(register int i=(x);i<=(y);++i)
#define DOR(i,x,y) for(register int i=(x);i>=(y);--i)
#define N 200003
typedef long long LL;
using namespace std;
void Read(int &x)
{
x=0;char ch=getchar();
for(;ch>'9'||ch<'0';ch=getchar());
for(;ch>='0'&&ch<='9';ch=getchar())x=(x<<3)+(x<<1)+ch-'0';
}
struct node{int w,v;}a[N];
int L[N],R[N],disc[N],n,m;
LL s[N],cnt[N],S,ans;
LL ABS(LL x){if(x<0)return -x;return x;}
LL solve(LL W)
{
LL sum=0;
FOR(i,1,n)
{
if(a[i].w>=W)cnt[i]=1,s[i]=a[i].v;
else cnt[i]=s[i]=0;
}
FOR(i,2,n)cnt[i]+=cnt[i-1],s[i]+=s[i-1];
FOR(i,1,m)sum+=(cnt[R[i]]-cnt[L[i]-1])*(s[R[i]]-s[L[i]-1]);
return sum;
}
int main()
{
scanf("%d%d%lld",&n,&m,&S);
FOR(i,1,n)Read(a[i].w),Read(a[i].v),disc[i]=a[i].w;
sort(disc+1,disc+1+n);
int tot=unique(disc+1,disc+1+n)-disc-1;
FOR(i,1,n)a[i].w=lower_bound(disc+1,disc+1+tot,a[i].w)-disc;
FOR(i,1,m)Read(L[i]),Read(R[i]);
ans=1e18;
int l=0,r=tot+1;
while(l<r)
{
int mid=l+r>>1;
if(solve(mid)<=S)
r=mid;
else l=mid+1;
}
FOR(i,-3,3)
ans=min(ans,ABS(S-solve(l+i)));
printf("%lld\n",ans);
return 0;
}