洛谷1314 聪明的质监员

聪明的质检员  https://www.luogu.org/problemnew/show/P1314#sub
小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 n 个矿石,从 1 
到 n 逐一编号,每个矿石都有自己的重量 wi 以及价值 vi。检验矿产的流程是: 
1、给定 m 个区间[Li,Ri]; 
2、选出一个参数 W; 
3、对于一个区间[Li,Ri],计算矿石在这个区间上的检验值 Yi : 
这批矿产的检验结果 Y 为各个区间的检验值之和。即: 
这里写图片描述 
调整参数 W 的值,让检验结果尽可能的靠近标准值 S,即使得 S-Y 的绝对值最小。请你帮忙求出这个最小值。 

公式解读:>=w的个数*价值和

显然可以二分答案一波~

注意:

1,long long 最大值可写0x7fffffffffffffff(15个f)

2,可以先判断再进行前缀和

sum[0]=0;	tot[0]=0;
for (i=1;i<=n;i++)
{
	if (w[i]>=x)
	{
		tot[i]=tot[i-1]+1;
		sum[i]=sum[i-1]+v[i];
	}
	else
	{
		tot[i]=tot[i-1];
		sum[i]=sum[i-1];
	}
}

3,搞清楚二分答案的大小判断

一个地方摔三次也是很牛批的。。。             

	while (l<=r)
	{
		mid=(l+r)/2;
		ans1=ans(mid);
		answer=min(answer,abs(ans1-s));
		if (ans1<s)
			r=mid-1;
		else
			l=mid+1;
	}
}

代码献上:

#include <cstdio>
#include <algorithm>
#include <cstring>

using namespace std;

const int maxSize=200000,maxValue=1000000;
long long n,m,s,max1,min1,answer=0x7fffffffffffffff;
long long a[maxSize+5][2],w[maxSize+5],v[maxSize+5];
long long tot[maxSize+5],sum[maxSize+5];

long long ans(long long x)
{
	long long i,y=0;
	
	sum[0]=0;	tot[0]=0;
	for (i=1;i<=n;i++)
	{
		if (w[i]>=x)
		{
			tot[i]=tot[i-1]+1;
			sum[i]=sum[i-1]+v[i];
		}
		else
		{
			tot[i]=tot[i-1];
			sum[i]=sum[i-1];
		}
	}
	for (i=0;i<m;i++)
		y+=(sum[a[i][1]]-sum[a[i][0]-1])*(tot[a[i][1]]-tot[a[i][0]-1]);
	return y;
}

void erfen()
{
	long long mid,l,r,ans1;
	
	l=min1;	r=max1;
	while (l<=r)
	{
		mid=(l+r)/2;
		ans1=ans(mid);
		answer=min(answer,abs(ans1-s));
		if (ans1<s)
			r=mid-1;
		else
			l=mid+1;
	}
}

int main()
{
	long long i;
	
	freopen("a.txt","r",stdin);
	scanf("%lld%lld%lld",&n,&m,&s);
	max1=0;	min1=maxValue;
	for (i=1;i<=n;i++)
	{
		scanf("%lld%lld",&w[i],&v[i]);
		max1=max(max1,w[i]);
		min1=min(min1,w[i]);
	}
	for (i=0;i<m;i++)
		scanf("%lld%lld",&a[i][0],&a[i][1]);
	
	erfen();
	printf("%lld\n",answer);
	
	return 0;
}

猜你喜欢

转载自blog.csdn.net/scutbenson/article/details/81879359