复习冲刺Noiping,单手打代码被神犇落下许多题,于是决定集中解决,结果。。。。。。一道题花0.5~1h,我都醉了。。。。。。
noip2011聪敏的质检员 题面:
【问题描述】
小 T 是一名质量监督员,最近负责检验一批矿产的质量。这批矿产共有 n 个矿石,从 1 到 n 逐一编号,每个矿石都有自己的重量 wi 以及价值 vi 。检验矿产的流程是:
1. 给定 m个区间 [Li,Ri] ;
2. 选出一个参数 W ;
3. 对于一个区间 [Li,Ri] ,计算矿石在这个区间上的检验值 Yi :
这批矿产的检验结果 Y 为各个区间的检验值之和。即:
一阵高大上的描述后,我死在了求和符号上(不断询问同机房神犇后才大致了解,写代码时也是各种出错。。。),由题意易推,当W越大时,Y越小,所以我们可以对M进行二分查找,当Y>S时向左区间查找,当Y<S时向右区间查找,当无法划分或Y=S时,结束二分,输出min{|Y-S|}最小即可
code:
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> using namespace std; struct hp{ long long l,r; }qes[200001]; struct hq{ long long w,v; }a[200001]; long long n,m,num[200001],sum[200001]; int main() { long long ans,i,j,w1,w2,t,maxn,x,wr2,s; freopen("qc.in","r",stdin); freopen("qc.out","w",stdout); n=m=s=0; scanf("%lld%lld%lld",&n,&m,&s); maxn=0; for (i=1;i<=n;++i) {a[i].v=a[i].w=0; scanf("%lld%lld",&a[i].w,&a[i].v); maxn=max(maxn,a[i].w);} for (i=1;i<=m;++i) { qes[i].l=qes[i].r=0; scanf("%lld%lld",&qes[i].l,&qes[i].r); } w1=1; wr2=w2=maxn; ans=0x7ffffffffffffff; while (true) { x=0; memset(sum,0,sizeof(sum)); memset(num,0,sizeof(num)); for (i=1;i<=n;++i) { sum[i]=sum[i-1]+(a[i].w>=w2)*a[i].v; num[i]=num[i-1]+(a[i].w>=w2); } for (i=1;i<=m;++i) x+=(sum[qes[i].r]-sum[qes[i].l-1])*(num[qes[i].r]-num[qes[i].l-1]); t=abs(x-s); ans=min(ans,t); if (x<=s) {wr2=w2; w2=(w1+w2)/2;} if ((x==s)||(w1==w2)) break; if (x>s) {w1=w2; w2=(w1+wr2)/2; } } cout<<ans<<endl; fclose(stdin); fclose(stdout); }