首先我们来看看观察每个区间的值
就以题目中的示例为例子解释一下
对应区间段1-5
由于可加的物品的重量必须大于等于W(4)
故在1-5中只有4,5两个可加贡献为 25+25=20;2是因为有两个数符号条件
在2-4中,只有4一个可加贡献为1*5=5;
3-3中,没有可以加的贡献0
故这样当w取4时候,贡献一共为25
这样我们可以看出这道题主要是求出某个区域的的值,这样我们便采用前缀和
我们可以采用一个sum数组来记录从前缀和,sum[i]表示从1到i之间所有有效数字的和
如果我们要求l,r之间的有效值,则可以用sum[r]-sum[i-1];
同理采用cnt数组来记录某个区间段有效物品的个数,cnt[i]表示从1到i之间有效物品的个数,
l,r之间的有效值个数即为cnt[r]-cnt[l-1];
故对应一个区间段的V值即为(cnt[r]-cnt[l-1])*(sum[r]-sum[l-1]);
#include<bits/stdc++.h>
using namespace std;
long long n,m,s;
long long sum[1000005];//用于前缀和存储
long long weight[1000005];//存储重量
long long value[1000005];//存储价值
int lefti[1000005];//存储区段的左结点
int righti[1000005];//存储区段右结点
int cnt[1000005];//存储有效数组的前缀
long long getsum(int w)//求出W=w时候,全部区域的V值和
{
long long ans=0;
for(int i=1;i<=n;i++)//先求出
{
if(weight[i]>=w)//如果满足条件
{
sum[i]=sum[i-1]+value[i];//加上这个物品的价值
cnt[i]=cnt[i-1]+1;//有效值加1
}
else
{
sum[i]=sum[i-1];
cnt[i]=cnt[i-1];
}
}
for(int i=1;i<=m;i++)
{
ans+=(cnt[righti[i]]-cnt[lefti[i]-1])*(sum[righti[i]]-sum[lefti[i]-1]);
}
return ans;
}
int main()
{
cnt[0]=0;
sum[0]=0;
int maxsize=-1;//用于记录最大值,便于后面确定二分法的起点
scanf("%lld%lld%lld",&n,&m,&s);
for(int i=1;i<=n;i++)
{
scanf("%lld %lld",&weight[i],&value[i]);
if(weight[i]>maxsize) maxsize=weight[i];
}
for(int i=1;i<=m;i++)
{
scanf("%d %d",&lefti[i],&righti[i]);
}
int l=0,r=maxsize+1;
int mid=(l+r+1)>>1;
int vis=0;//判断是否有差为0情况
while(l<r)
{
if(getsum(mid)>s)因为大于标准,则说明w取小了让很多物体都符合条件,故要增加w
{
l=mid;
}
else if(getsum(mid)<s)
{
r=mid-1;
}
else
{
printf("0");
vis=1;
break;
}
mid=(l+r+1)>>1;
}
if(!vis) printf("%lld",min(abs(s-getsum(r+1)),abs(getsum(r)-s)));
}
最后祝大家天天AC,坚持下去!

京公网安备 11010502036488号