【NOIP2011提高组T5】聪明的质监员-二分答案+前缀和
2016-10-27 11:38
369 查看
测试地址:聪明的质监员
做法:可以发现,Y的值是随着W的递增而递减的,满足单调性,因此可以用二分答案把查找答案的复杂度降为O(log n)。设lf为左边界,rt为右边界,lf初始化为0,rt初始化为最大的w[i]+1(即矿石中一个都不满足w[i]≥W的情况),然后进行二分答案。设mid=(lf+rt)/2,对于每个mid,算出Y的值,如果Y<S,则表示左半区间内的数更靠近S,否则表示右半区间内的数更靠近S(想一想,为什么?),一次次地缩小查找范围,就可以找到最好的W了。
那么现在我们只需解决求Y值的问题,由于区间有m个,如果求每个区间的Yi时都要O(n)的复杂度的话,那么整个求Y值的过程的复杂度就是O(nm),显然是不可能承受的。再分析Yi的特征,发现其由两部分组成:w[i]≥W的矿石数量和它们的价值之和。这两个部分都是一个求和的关系,又考虑到在W相同的情况下,这个区间内数的值是不会变化的,所以我们用两个数组sum1和sum2分别表示区间[1,i]内的w[i]≥W的矿石数量和它们的价值之和,那么如果我们要求一个区间[l,r]的Yi,则:
Yi=(sum1[r]-sum1[l-1])*(sum2[r]-sum2[l-1])
这样一来,求Yi的复杂度就降为O(1)了,而sum1和sum2只需计算一次,复杂度为O(n),因而整个求Y值的过程的时间复杂度就是O(n+m),在加上二分答案,整个程序的复杂度就是O((n+m)log n),问题完美解决。
以下是本人代码:
做法:可以发现,Y的值是随着W的递增而递减的,满足单调性,因此可以用二分答案把查找答案的复杂度降为O(log n)。设lf为左边界,rt为右边界,lf初始化为0,rt初始化为最大的w[i]+1(即矿石中一个都不满足w[i]≥W的情况),然后进行二分答案。设mid=(lf+rt)/2,对于每个mid,算出Y的值,如果Y<S,则表示左半区间内的数更靠近S,否则表示右半区间内的数更靠近S(想一想,为什么?),一次次地缩小查找范围,就可以找到最好的W了。
那么现在我们只需解决求Y值的问题,由于区间有m个,如果求每个区间的Yi时都要O(n)的复杂度的话,那么整个求Y值的过程的复杂度就是O(nm),显然是不可能承受的。再分析Yi的特征,发现其由两部分组成:w[i]≥W的矿石数量和它们的价值之和。这两个部分都是一个求和的关系,又考虑到在W相同的情况下,这个区间内数的值是不会变化的,所以我们用两个数组sum1和sum2分别表示区间[1,i]内的w[i]≥W的矿石数量和它们的价值之和,那么如果我们要求一个区间[l,r]的Yi,则:
Yi=(sum1[r]-sum1[l-1])*(sum2[r]-sum2[l-1])
这样一来,求Yi的复杂度就降为O(1)了,而sum1和sum2只需计算一次,复杂度为O(n),因而整个求Y值的过程的时间复杂度就是O(n+m),在加上二分答案,整个程序的复杂度就是O((n+m)log n),问题完美解决。
以下是本人代码:
#include <cstdio> #include <cstdlib> #include <cstring> #include <iostream> #include <algorithm> #define ll long long using namespace std; ll n,m,S,w[200010],v[200010],lf=0,rt=0,ans; ll sum1[200010]={0},sum2[200010]={0}; int l[200010],r[200010]; ll ab(ll a) { if (a<0) return -a; else return a; } bool calc(ll W) { sum1[0]=sum2[0]=0; for(int i=1;i<=n;i++) { sum1[i]=sum1[i-1];sum2[i]=sum2[i-1]; if (w[i]>=W) sum1[i]++,sum2[i]+=v[i]; } ll s=0; for(int i=1;i<=m;i++) s+=(sum1[r[i]]-sum1[l[i]-1])*(sum2[r[i]]-sum2[l[i]-1]); if (ab(s-S)<ans) ans=ab(s-S); return s<S; } int main() { scanf("%lld%lld%lld",&n,&m,&S); for(int i=1;i<=n;i++) { scanf("%lld%lld",&w[i],&v[i]); rt=max(rt,w[i]); } rt++; for(int i=1;i<=m;i++) scanf("%d%d",&l[i],&r[i]); ans=1000000; ans=ans*ans; while(lf<=rt) { ll mid=(lf+rt)>>1; if (calc(mid)) rt=mid-1; else lf=mid+1; } printf("%lld",ans); return 0; }
相关文章推荐
- LuoguP1314[NOIP2011] 聪明的质监员 解题报告【二分答案+前缀和】
- 二分查找前缀和(洛谷1314聪明的质监员NOIP2011提高组)
- 【noip2011提高组】 聪明的质监员 前缀和+二分
- noip2011 聪明的质监员 (二分+前缀和处理+读入优化)
- [NOIP2011] 聪明的质监员 二分+前缀和
- 聪明的质监员 2011年NOIP全国联赛提高组(二分+前缀和)
- 离散+二分+前缀和 [NOIP2011] 聪明的质监员
- NOIP2011 聪明的质监员 解题报告(二分+ 前缀和处理)
- [NOIP2011]聪明的质监员 D2 T2 二分答案
- NOIP 2011 - 提高组 聪明的质检员 二分+前缀和 重庆一中高2018级竞赛班第六次测试 2016.7.31 Problem 2
- NOIP2011提高组 聪明的质检员(二分答案)
- 洛谷P1314 [NOIP2011提高组Day2T2] 聪明的质监员
- NOIP2011提高组 聪明的质监员 -SilverN
- NOIP2011复赛提高组day2(A:计算系数 B:聪明的质监员 C:观光公交)
- NOIP2011 聪明的质监员(二分)
- [NOIP 2011] 聪明的质检员:二分,前缀和
- 【二分】【Noip2011】聪明的质监员
- Luogu P1314 [NOIp提高组2011]聪明的质监员
- NOIP2011提高组 聪明的质监员 -SilverN
- NOIP 2011 提高组 聪明的质监员