JZOJ 3028. 聪明的质监员 (Standard IO) NOIP2011
题目
大意
在有N个数的数列中,找到一个W的值,计算后使其最接近s
分析
首先我们可以发现,加起来的和h,是和W有关系的
w越大,我们所求得的和就越小 如果h>s 我们要尽量减小 否 增大
所以我们能想到用二分,找到最贴近的
可就算如此还是超时了
所以我们还是要用到前缀和优化
attention ll
代码
1 #include<iostream> 2 #include<cmath> 3 #include<cstring> 4 #define N 2000001 5 using namespace std; 6 int w[N],v[N]; 7 int l[N],r[N]; 8 long long sum; 9 long long sum1[N],sum2[N]; //sum1计算前缀个数,sum2计算前缀价值 10 long long n,m,s; 11 bool count(int key) 12 { 13 memset(sum1,0,sizeof(sum1)); 14 memset(sum2,0,sizeof(sum2)); 15 for (int i=1;i<=n;i++) 16 { 17 if (w[i]>=key) 18 { 19 sum1[i]=sum1[i-1]+1; 20 sum2[i]=sum2[i-1]+v[i]; 21 } 22 else 23 { 24 sum1[i]=sum1[i-1]; 25 sum2[i]=sum2[i-1]; 26 } 27 } 28 long long ans=0; 29 for (int i=1;i<=m;i++) 30 ans+=(sum1[r[i]]-sum1[l[i]-1])*(sum2[r[i]]-sum2[l[i]-1]); //计算总和 31 sum=(long long)abs(ans-s); 32 if (ans>s) return true; 33 return false; 34 } 35 int main () 36 { 37 int mn,mx; 38 cin>>n>>m>>s; 39 for (int i=1;i<=n;i++) 40 { 41 cin>>w[i]>>v[i]; 42 mx=max(mx,w[i]); 43 mn=min(mn,w[i]); 44 } 45 for (int i=1;i<=m;i++) 46 cin>>l[i]>>r[i]; 47 int left=mn-1,right=mx+2,mid; 48 long long ans=999999999999999; 49 while (left<=right) 50 { 51 mid=(left+right)/2; 52 if (count(mid)) left=mid+1; //如果大于我的s就尽可能的W变大 53 else right=mid-1; //如果小于我就变小 54 ans=min(ans,sum); //求一个最小值 55 } 56 cout<<ans; 57 }
为何要逼自己长大,去闯不该闯的荒唐