2024.6.3练习情况—整数二分
一、洛谷P1873 [COCI 2011/2012 #5] EKO / 砍树
-
题目
-
分析
参考题解完成。在这个题中数据量很大,是10的9次方,要考虑开longlong。单纯用暴力使用for循环的话肯定是要暴空间和时间的,所以要考虑优化使用二分。
题中要求所有树的高度总和 > M,也就是说不可能要求将树全部砍到。这是我们可以确定二分的左右边界是所给出树高度的最大值和最小值。分别用minn和maxx记录。
这个题要求锯片的最高高度也就是要求给出能满足要求的最大值。这里思考的是使用求右端点的二分模板,并在if判断语句里再使用check函数。在check函数里判断当前值mid是否满足条件,即sum+=(arr[i]-mid)是否大于等于m,如果check函数返回true,则说明设置的锯片高度低了,需要将l=mid。
代码
#include<iostream> #include<algorithm> using namespace std; const int N = 1000010; int n; long long m; int arr[N]; long long sum; bool check(int arr[],int mid){ sum=0; for(int i=0;i<n;i++){ if(arr[i]>mid){ sum+=(arr[i]-mid); } } if(sum>=m) return true; else return false; } int main() { cin>>n>>m; for(int i=0;i<n;i++){ cin>>arr[i]; } sort(arr,arr+n);
int maxx=arr[n-1]; int minn=arr[0];
int l=minn,r=maxx; while(l<r){ int mid=(l+r+1)/2; if(check(arr,mid)) l=mid; else r=mid-1; } cout<<l<<endl; return 0; } |
-
运行评判结果
三、复习洛谷P1102 A-B 数对
-
题目
-
分析
完全独立完成。针对练习的算法整数二分加上昨天学习题解的方法对这个题进行思考,因为题中说每个位置都算不同的结果,所以可以使用for循环将每个位置b加上c找到对应的A,并在数列中找到A的左右端的编号ll和rr。将每个位置找到的(rr-ll+1)相加就是最后结果。注意使用这种方法时要先将数列排序。
-
代码
代码:
#include<iostream> #include<algorithm> using namespace std; const int N = 200010; int n,c; long long ans; int arr[N]; //找左端,左端大右 int findleft(int arr[],int k){ int l=0,r=n-1; while(l<r){ int mid=(l+r)/2; if(arr[mid]>=k){ r=mid; } else l=mid+1; } if(arr[l]==k){ return l; } return -1; } //找右端,右端小左 int findright(int arr[],int k){ int l=0,r=n-1; while(l<r){ int mid=(l+r+1)/2; if(arr[mid]<=k){ l=mid; } else r=mid-1; } if(arr[l]==k){ return l; } else return -1; } int main() { cin>>n>>c; for(int i=0;i<n;i++){ cin>>arr[i]; } //要先对数列排序 sort(arr,arr+n); //因为每个位置都算不同的结果 for(int i=0;i<n;i++){ int temp=arr[i]+c; int ll=findleft(arr,temp); if(ll==-1) continue; else{ int rr=findright(arr,temp); ans+=(rr-ll+1); } } cout<<ans<<endl; return 0; } |
-
运行评判结果