题意
你有
n
n
n个零件,给你
m
m
m个区间,其中:
y
i
=
∑
i
=
l
i
r
i
(
a
[
i
]
.
w
>
W
)
∗
∑
i
=
l
i
r
i
(
a
[
i
]
.
w
>
W
)
∗
a
[
i
]
.
v
y_i=\sum_{i=l_i}^{r_i}(a[i].w>W)*\sum_{i=l_i}^{r_i}(a[i].w>W)*a[i].v
yi=i=li∑ri(a[i].w>W)∗i=li∑ri(a[i].w>W)∗a[i].v
然后你可以调整
W
W
W,使得
∣
∑
y
i
−
K
∣
|\sum y_i-K |
∣∑yi−K∣最小并输出这个值
解题方法
我们发现 Y ( w ) Y(w) Y(w)是一个单调递减的函数,所以就可以通过二分来求得最优答案,但是在二分判断的时候该如何快速解决呢?我们需要一个前缀和预处理一下,然后再枚举区间计算就可以了,复杂度是 O ( ( n + m ) × l o g w m a x ) O ( (n+m) \times log w_{max} ) O((n+m)×logwmax)。
代码
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
struct node
{
long long w,v;
}a[400001];
long long l[400001],r[400001];
long long n,m;
long long s;
long long ans;
long long b[400001];
long long c[400001];
long long tot;
long long he1[400001];
long long he2[400001];
bool check(long long x)
{
memset(he1,0,sizeof(he1));
memset(he2,0,sizeof(he2));
for(long long i=1;i<=n;i++)
{
he1[i]=he1[i-1];
he2[i]=he2[i-1];
if(a[i].w>=x)
{
he1[i]+=a[i].v;
he2[i]++;
}
}
long long he=0;
for(long long i=1;i<=m;i++)
{
he+=(he1[r[i]]-he1[l[i]-1])*(he2[r[i]]-he2[l[i]-1]);
}
ans=min(ans,abs(he-s));
if(he>s)return 1;
else return 0;
}
void erfen(long long l,long long r)
{
if(l>=r)
{
return;
}
long long mid=(l+r)/2;
if(check(c[mid]))
{
erfen(mid+1,r);
}
else
{
erfen(l,mid);
}
}
int main()
{
scanf("%lld%lld%lld",&n,&m,&s);
for(long long i=1;i<=n;i++)
{
scanf("%lld%lld",&a[i].w,&a[i].v);
b[i]=a[i].w;
}
for(long long i=1;i<=m;i++)
{
scanf("%lld%lld",&l[i],&r[i]);
}
sort(b+1,b+n+1);
b[0]=-1e5;
for(long long i=1;i<=n;i++)
{
if(b[i]!=b[i-1])
{
tot++;
c[tot]=b[i];
}
}
c[0]=0;
c[tot+1]=b[n]+1;
ans=(long long)(1ll<<60)-1;
erfen(0,tot+1);
cout<<ans<<'\n';
return 0;
}