版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_36404449/article/details/78276906
题目描述 Description |
---|
小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有n 个矿石,从1到n 逐一编号,每个矿石都有自己的重量wi 以及价值vi。检验矿产的流程是:见图 |
若这批矿产的检验结果与所给标准值S 相差太多,就需要再去检验另一批矿产。小T不想费时间去检验另一批矿产,所以他想通过调整参数W 的值,让检验结果尽可能的靠近标准值S,即使得S-Y 的绝对值最小。请你帮忙求出这个最小值。 |
输入描述 Input Description |
第一行包含三个整数 n,m,S,分别表示矿石的个数、区间的个数和标准值。接下来的 n 行,每行2 个整数,中间用空格隔开,第i+1 行表示i 号矿石的重量wi 和价值vi 。 接下来的 m 行,表示区间,每行2 个整数,中间用空格隔开,第i+n+1 行表示区间[Li,Ri]的两个端点Li 和Ri。注意:不同区间可能重合或相互重叠。 |
输出描述 Output Description |
输出只有一行,包含一个整数,表示所求的最小值。 |
水题分析 Waterproblem Analysis |
也是夏令营二分的必讲题,因为是对于区间求和而且区间数目多不方便暴力枚举,就很显然是要求一个前缀和了,对于每一个二分值求一个前缀和即可。注意数据范围比较大,用long long类型就可以过了。这个题比较水,而且不是DP不用过多分析,就显得的整篇博文很短,其实没什么关系,只要贴一个代码就很长了。 |
附上代码:
#include<iostream>
#include<cmath>
#include<cstdio>
#define ll long long
#define MAXN 200010
using namespace std;
ll n,m,s;
int w[MAXN],v[MAXN];
long long dv[MAXN],t[MAXN],ans=0;
long long anss=21474836400006;
struct re
{
int l,r;
}q[MAXN];
inline ll get_num()
{
ll num=0;
char c;
bool flag=1;
while((c=getchar())=='\n'||c=='\r'||c==' ');
if(c=='-')flag=0;
else num=c-'0';
while(isdigit(c=getchar()))
num=num*10+c-'0';
return num*(flag?1:-1);
}
bool cheak(ll mid)
{
for(int i=1;i<=n;i++)
{
if(w[i]>=mid)
{
t[i]=t[i-1]+1;
dv[i]=dv[i-1]+v[i];
}
else
{
t[i]=t[i-1];
dv[i]=dv[i-1];
}
}
ans=0;
for(int i=1;i<=m;i++)
{
ans+=(dv[q[i].r]-dv[q[i].l-1])*(t[q[i].r]-t[q[i].l-1]);
}
ll x=abs(ans-s);
anss=min(anss,x);
if(ans>=s)return 1;
else return 0;
}
int main()
{
n=get_num();m=get_num();s=get_num();
for(int i=1;i<=n;i++)
{
w[i]=get_num();
v[i]=get_num();
}
for(int i=1;i<=m;i++)
{
q[i].l=get_num();
q[i].r=get_num();
}
ll l=1,r=2147483646000;//这里之前r过小也没有AC
while(l<=r)
{
ll mid=(l+r)>>1;
if(cheak(mid))l=mid+1;
else r=mid-1;
}
cout<<anss;
}