[noip2011d2t2]聪明的质检员 二分+前缀和优化
近期卡的时间最长的一道题了qaq
题目链接:https://www.luogu.org/problem/show?pid=1314
光理解那个公式就理解了半天
每个区间的Y值=(该区间重量大于选定的W的点的个数)*(这些点的价值之和)
读懂题意后,可以发现显然Y随着W的增大而减小,具有单调性
由此可以想到二分
那么对于二分的每个W值,要如何求出检验值Y呢?
对于每个区间一一判断显然不满足数据规模
因为W值确定之后,每个点对答案有无贡献就已经确定。因此可以对于每个W值,预处理出一个类似于前缀和的数组储存满足条件的点的信息
就可以在O(m)的时间内算出Y值
这个优化方法要熟练运用==
1 #include<cstdio> 2 #include<cstring> 3 #include<algorithm> 4 #include<cmath> 5 #define ll long long 6 #define inf (1LL<<60) 7 using namespace std; 8 const int maxn=200200; 9 const int maxm=200200; 10 ll n,m,s; 11 ll minw,maxw; 12 ll w[maxn],v[maxn],L[maxm],R[maxm]; 13 ll cnt[maxn],sum[maxn]; 14 ll read(){ 15 ll x=0; 16 char ch=getchar(); 17 while (ch<'0'||ch>'9') ch=getchar(); 18 while (ch>='0'&&ch<='9'){ 19 x=x*10+ch-'0'; 20 ch=getchar(); 21 } 22 return x; 23 } 24 ll check(ll W){ 25 memset(cnt,0,sizeof(cnt)); 26 memset(sum,0,sizeof(sum)); 27 for (ll i=1;i<=n;i++){ 28 cnt[i]=cnt[i-1]; 29 sum[i]=sum[i-1]; 30 if (w[i]>=W){ 31 cnt[i]++; 32 sum[i]+=v[i]; 33 } 34 } 35 ll tmp=0; 36 for (ll i=1;i<=m;i++) 37 tmp+=(cnt[R[i]]-cnt[L[i]-1])*(sum[R[i]]-sum[L[i]-1]); 38 return tmp; 39 } 40 int main(){ 41 n=read(),m=read(),s=read(); 42 maxw=0; 43 for (ll i=1;i<=n;i++){ 44 w[i]=read(),v[i]=read(); 45 maxw=max(maxw,w[i]); 46 } 47 for (ll i=1;i<=m;i++){ 48 L[i]=read(),R[i]=read(); 49 } 50 ll l=0,r=maxw+1,ans=inf; 51 while (l<=r){ 52 ll mid=(l+r)>>1; 53 ll t=check(mid); 54 ans=min(ans,abs(t-s)); 55 if (t<s) r=mid-1; 56 else l=mid+1; 57 } 58 printf("%lld\n",ans); 59 return 0; 60 }
11天倒计时