标签:二分 总结 int sum mid long 算法 查找
日期:2022年5月19日
注:本博客仅供参考
概念与基本思路
二分算法是一种在有序数组中查找某一特定元素的查找算法。查找过程从数组的中间元素开始:如果中间元素正好是要查找的元素,则查找过程结束;如果某一特定元素大于或者小于中间元素,则在数组大于或小于中间元素的那一半中查找,而且跟开始一样从中间元素开始比较。
与分治的关系
二分可以看作为一种特殊的分治
要求
数据一定要是有序的(单调的),不能乱序。
实现方法
用L(left)和R(right)代表某一区域的范围。L与R相加除以二计算出中间值mid的值,若答案在mid的左边,则R=mid-1;若答案在mid的右边,则L=mid。重复这个过程,直到L与R中间只有一个元素,此时这个元素就是要寻找的答案。
代码
二分查找
查找小于等于某个数的最大值
1 #include<bits/stdc++.h> 2 using namespace std; 3 int len,n[10100],want; 4 int main(){ 5 scanf("%d%d",&len,&want); 6 sort(n,n+len);//默认是升序排列的 7 int L=1,R=len,mid; 8 while(L<R) 9 { 10 mid=(L+R+1)/2; 11 if(n[mid]<=want) 12 { 13 L=mid; 14 }else{ 15 R=mid-1; 16 } 17 } 18 printf("%d",L); 19 return 0; 20 }
查找大于等于它的最小值
1 1 #include<bits/stdc++.h> 2 2 using namespace std; 3 3 const int N=1001000; 4 4 int n,m,q,a[N]; 5 5 int L,R,mid; 6 6 int main(){ 7 7 scanf("%d%d",&n,&m); 8 8 for(int i=1;i<=n;++i) 9 9 { 10 10 scanf("%d",&a[i]); 11 11 } 12 12 for(int i=1;i<=m;++i) 13 13 { 14 14 L=1,R=n; 15 15 scanf("%d",&q); 16 16 while(L<R) 17 17 { 18 18 mid=(L+R)/2; 19 19 if(a[mid]>=q) 20 20 { 21 21 R=mid; 22 22 }else{ 23 23 L=mid+1; 24 24 } 25 25 } 26 26 if(a[L]!=q) 27 27 { 28 28 printf("%d ",-1); 29 29 }else{ 30 30 printf("%d ",L); 31 31 } 32 32 } 33 33 return 0; 34 34 }
砍树(P1873)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int tree=1000100; 4 int N,M,trees[tree]; 5 int L,R,mid,mx=0; 6 int check(int a){ 7 long long sum=0; 8 for(int i=1;i<=N;++i) 9 { 10 if(trees[i]>=a) 11 { 12 sum+=trees[i]-a; 13 } 14 } 15 return sum>=M; 16 } 17 int main(){ 18 scanf("%d%d",&N,&M); 19 for(int i=1;i<=N;++i) 20 { 21 scanf("%d",&trees[i]); 22 mx=max(mx,trees[i]); 23 } 24 L=0,R=mx; 25 while(L<R) 26 { 27 mid=(L+R+1)/2; 28 if(check(mid)) 29 { 30 L=mid; 31 }else{ 32 R=mid-1; 33 } 34 } 35 printf("%d",L); 36 return 0; 37 }
木材加工(P2440)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int n,k,woods[100100]; 4 int L,R,mid,mx=0; 5 int check(int a){ 6 long long sum=0; 7 for(int i=1;i<=n;++i) 8 { 9 sum+=woods[i]/a; 10 } 11 return sum>=k; 12 } 13 int main(){ 14 scanf("%d%d",&n,&k); 15 for(int i=1;i<=n;++i) 16 { 17 scanf("%d",&woods[i]); 18 mx=max(mx,woods[i]); 19 } 20 L=0,R=mx; 21 while(L<R) 22 { 23 mid=(L+R+1)/2; 24 if(check(mid)) 25 { 26 L=mid; 27 }else{ 28 R=mid-1; 29 } 30 } 31 printf("%d",L); 32 return 0; 33 }
跳石头(P2678)
1 #include<bits/stdc++.h> 2 using namespace std; 3 int L,N,M,rocks[50100]; 4 int l,r,mid; 5 int check(int a){ 6 int sum=0,cu=0; 7 for(int i=1;i<=N;++i) 8 { 9 if(rocks[i]-rocks[cu]<a) 10 { 11 ++sum; 12 }else{ 13 cu=i; 14 } 15 } 16 return sum<=M; 17 } 18 int main(){ 19 scanf("%d%d%d",&L,&N,&M); 20 for(int i=1;i<=N;++i) 21 { 22 scanf("%d",&rocks[i]); 23 } 24 l=0,r=L; 25 while(l<r) 26 { 27 mid=(l+r+1)/2; 28 if(check(mid)) 29 { 30 l=mid; 31 }else{ 32 r=mid-1; 33 } 34 } 35 printf("%d",l); 36 return 0; 37 }
A-B数对(P1102)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=200100; 4 int n,c,a[N]; 5 int L,R,mid,sum=0; 6 int main(){ 7 scanf("%d%d",&n,&c); 8 for(int i=1;i<=n;++i) 9 { 10 scanf("%d",&a[i]); 11 } 12 sort(a+1,a+n+1); 13 for(int i=1;i<=n-1;++i) 14 { 15 L=i+1,R=n; 16 while(L<=R) 17 { 18 mid=(L+R)/2; 19 if(a[mid]>=a[i]+c) 20 { 21 R=mid-1; 22 }else{ 23 L=mid+1; 24 } 25 } 26 sum-=L; 27 L=i+1,R=n; 28 while(L<=R) 29 { 30 mid=(L+R)/2; 31 if(a[mid]>a[i]+c) 32 { 33 R=mid-1; 34 }else{ 35 L=mid+1; 36 } 37 } 38 sum+=L; 39 } 40 printf("%d",sum); 41 return 0; 42 }
聪明的质监员(P1314)
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int N=200100; 4 int n,m,w[N],v[N],l[N],r[N],L,R,mid,c[N]; 5 long long s,sum[N]; 6 long long y(int a){ 7 memset(c,0,sizeof(c)); 8 memset(sum,0,sizeof(sum)); 9 for(int i=1;i<=n;++i) 10 { 11 c[i]=c[i-1]+(w[i]>=a);//这里使用了前缀和的知识 12 } 13 for(int i=1;i<=n;++i) 14 { 15 sum[i]=sum[i-1]+(w[i]>=a)*v[i]; 16 } 17 long long res=0; 18 for(int i=1;i<=m;++i) 19 { 20 res+=(c[r[i]]-c[l[i]-1])*(sum[r[i]]-sum[l[i]-1]); 21 } 22 return res; 23 } 24 int main(){ 25 scanf("%d%d%lld",&n,&m,&s); 26 for(int i=1;i<=n;++i) 27 { 28 scanf("%d%d",&w[i],&v[i]); 29 } 30 for(int i=1;i<=m;++i) 31 { 32 scanf("%d%d",&l[i],&r[i]); 33 } 34 L=0,R=1000000; 35 while(L<R) 36 { 37 mid=(L+R)/2; 38 if(y(mid)<=s) 39 { 40 R=mid; 41 }else{ 42 L=mid+1; 43 } 44 } 45 long long ans=min(s-y(L),y(L-1)-s); 46 printf("%lld\n",ans); 47 return 0; 48 }
心得
- 二分算法虽然非常好用、高效,但做题时也要思考这道题是否需要使用二分算法。
- 二分算法的二分查找部分几乎相等,变化的一般只是检验部分。
- 二分算法与一些其他的算法/思想(如贪心、前缀和等)一起使用可以实现意想不到的效果。如跳石头(P2678)的检验函数:
1 int check(int a){ 2 6 int sum=0,cu=0; 3 7 for(int i=1;i<=N;++i) 4 8 { 5 9 if(rocks[i]-rocks[cu]<a) 6 10 { 7 11 ++sum; 8 12 }else{ 9 13 cu=i; 10 14 } 11 15 } 12 16 return sum<=M; 13 17 }
标签:二分,总结,int,sum,mid,long,算法,查找 来源: https://www.cnblogs.com/PlayerSS05/p/16287978.html
本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享; 2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关; 3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关; 4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除; 5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。