题意分析
有 个物品,每件物品有自己的重量 和价值 ,现在给定 个区间,一个参数 和一个标准值 。
已知:
现在我们想要调整 的值 ,使得最小,求出这个最小值。
算法分析
题目中,时间卡的很紧,只能支持一维循环,可是我们还要找 ,而且 范围为,肯定是不能循环爆搜,那么就可以用二分查找,毕竟二分查找在int范围内也是常数的时间复杂度,再加上计算y的一维复杂度,可以做。
那么先来组织算y的代码:我们容易发现这个求和是在一个区间内所有满足条件的数的和,很容易想到前缀和,那么每次二分求一次前缀和,区间和就是(注意这个-1,蒟蒻作者甚至错了),y的因数分别求前缀和,算出y。
然后是二分,查找的范围很容易想到是和的范围,所以设,,在这个范围内进行二分查找,再来证明一下单调性:由y的计算公式易得当较大时,能取到的和少,那么它们区间和的乘积自然小,由此可以推出该二分应是单调递减的。
代码实现
#include<bits/stdc++.h>
using namespace std;
const int N=200010;
int n,m;
long long s;
int w[N],v[N];
int l[N],r[N];
long long sw[N],sv[N];
long long ans=0x3f3f3f3f3f3f3f3f;
long long chk(int mid)
{
memset(sw,0,sizeof(sw));
memset(sv,0,sizeof(sv));
for(int i=1;i<=n;++i)
{
if(w[i]>=mid)
{
sw[i]=sw[i-1]+1;
sv[i]=sv[i-1]+v[i];
}
else
{
sw[i]=sw[i-1];
sv[i]=sv[i-1];
}
}
long long y=0;
for(int i=1;i<=m;++i)
{
y+=(sw[r[i]]-sw[l[i]-1])*(sv[r[i]]-sv[l[i]-1]);
}
return y;
}
int main()
{
scanf("%d%d%lld",&n,&m,&s);
for(int i=1;i<=n;++i) scanf("%d%d",&w[i],&v[i]);
for(int i=1;i<=m;++i) scanf("%d%d",&l[i],&r[i]);
int lc=0,rc=1e6;
while(lc<rc)
{
int mid=(lc+rc)/2;
if(chk(mid)>s) lc=mid+1;
else rc=mid;
ans=min(abs(chk(mid)-s),ans);
}
printf("%lld",ans);
return 0;
}
后记
本体的思路还是很简单的,代码其实也就是一个二分模板,但即便简单如此,也会有一些小坑,如果注意不到那就是满盘皆输。