FZU ACM 寒假第二讲:二分法

第一题:

include<bits/stdc++.h>

using namespace std;
bool search(const vector&arr,int target){
int l=0,r=arr.size()-1;
while(l<=r){
int mid=l+(r-l)/2;
if(arr[mid]==target){
return true;
}else if(arr[mid]<target){
l=mid+1;
}else{
r=mid-1;
}
}return false;
}
int main(){
int n;
cin>>n;
vectorarr(n);
for(int i=0;i<n;i++){
cin>>arr[i];
}
int q;
cin>>q;
for(int i=0;i<q;i++){
int m;
cin>>m;
if(search(arr,m)){
cout<<"Yes"<<endl;
}else{
cout<<"No"<<endl;
}
}return 0;
}
思路:套用二分查找模板即可解题
第二题:

include<bits/stdc++.h>

using namespace std;
int main(){
long long int n,c;
long long int k;
long long sum=0;
cin>>n>>c;
vectora(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
sort(a.begin(),a.end());
for(int i=0;i<n;i++){
long long int l=0,r=n-1;
while(l<r){
long long int mid=(l+r)/2;
if(a[i]-a[mid]<=c)
r=mid;
else l=mid+1;
}
if(a[i]-a[l]==c)k=l;
else continue;
l=k-1;
r=n-1;
while(l<r){
long long int mid=(l+r+1)/2;
if(a[i]-a[mid]>=c)
l=mid;
else r=mid-1;
}
sum+=l-k+1;
}
cout<<sum;
return 0;
}
思路:我想的是看成A-C=B,C已知,更易理解,然后套用二分查找模板
第三题:

include<bits/stdc++.h>

using namespace std;
bool check(const vector& h,const vector& w,int x,int y,int n){
int sum=0;
for(int i=0;i<n;i++){
sum+=(h[i]/x)*(w[i]/x);
}
if(sum>=y){
return true;
}
else return false;

}
int main(){
int n,k;
int max=0;
cin>>n>>k;
vector h(n);
vector w(n);
for(int i=0;i<n;i++){
cin>>h[i]>>w[i];
if(h[i]>max){
max=h[i];
}
if(w[i]>max){
max=w[i];
}
}
int l=1,r=max;
while(l<r){
int mid=l+r+1>>1;
if(check(h,w,mid,k,n)) l=mid;
else r=mid-1;
}
cout<<l;
return 0;
}
思路:先计算每块巧克力可以分出几块,把块数相加起来判断是否大于小朋友的人数,用check函数实现,在套用二分模板,尽可能大
第四题:

include<bits/stdc++.h>

using namespace std;
bool check(const vector& a,const vector& b,long long int x,long long int n,long long int m){
long long int sum=0;
for(int i=0;i<n;i++){
if(a[i]+b[i]<x) return false;
if(x>a[i]) sum+=x-a[i];
}
if(sum>m) return false;
else return true;

}
int main(){
long long int max=0;
long long int n,m;
cin>>n>>m;
vector a(n);
vector b(n);
for(int i=0;i<n;i++){
cin>>a[i];
}
for(int i=0;i<n;i++){
cin>>b[i];
if(a[i]+b[i]>max){
max=a[i]+b[i];
}
}
long long int l=1,r=max;
while(l<r){
long long int mid=l+r+1>>1;
if(check(a,b,mid,n,m)){
l=mid;
}
else r=mid-1;
}
cout<<l;
return 0;
}
思路:主函数l是至少还有一套,r是最大的可能套数,看空白牌是否能够达到目标套数用check函数实现
第五题:

include <bits/stdc++.h>

using namespace std;
long long int n,m;
long long int t,num;
long long a[505];
long long int x[505],y[505];
bool check(int s) {
int num=1,t=0;
for(int i=n;i>=1;i--) {
if(t+a[i]>s) t=0,num++;
t+=a[i];
}
return num<=m;
}

int find(int low,int high) {
int mid;
while(low+1<high){
mid=low+(high-low)/2;
if(check(mid))
high=mid;
else
low=mid;
}
return high;
}

int main()
{ long long l=0,h=0;
cin>>n>>m;
for(int i=1;i<=n;i++){
cin>>a[i];
h+=a[i];
l=max(l,a[i]);
}
long long int s=find(l,h);
long long int t=0,num=1;
for(int i=1;i<=m;i++)
x[i]=y[i]=0;
y[1]=n;
for(int i=n;i>=1;i--) {
if(t+a[i]>s) {
t=0;
x[num]=i+1;
y[++num]=i;
}
t+=a[i];
}
x[num]=1;

for(int i=m;i>=1;i--)	
	cout<<x[i]<<" "<<y[i]<<endl;
return 0;

}
思路:用主函数查出最多的页数,为了让后面的人有更长的时间,要用check函数倒序检查页数大于mid时人数加1看人数是否符合条件,定义x,y记录第一本和最后一本,分别记录并输出
第六题:青蛙过河

include

using namespace std;
int ren(int mid,int a[],int n,int x)
{
int k=1,s[100000],i;
s[0]=0;
for(i=1;i<n;i++){
s[i]=s[i-1]+a[i];
}
for(i=1;i<n-mid+1;i++){
if(s[i+mid-1]-s[i-1]<x*2){
k=0;
break;
}
}

return k;

}

int main()
{
int n,x,a[100000],l,r,mid;
cin>>n>>x;
for(int i=1;i<n;i++){
cin>>a[i];
}
l=1;
r=n;
while(l<r){
mid=(l+r)/2;
if(ren(mid,a,n,x))r=mid;
else l=mid+1;
}
cout<<l;
return 0;
}
思路:用二分查找找到跳跃能力,然后用ren函数,利用条件:在1到mid上高度和一定大于等于2x;区间[2,mid]能容纳2x-hmid+1只青蛙,可以让多出来的几只跳到[2,y]中
学习总结:学习了二分查找模板,并了解了一些细节,学习了如何使用二分查找解决问题,在思路上,了解了什么叫“贪心”,并学会找出题目中隐含的充分条件与必要条件,但在解题思路上还存在困难,需要多加练习

posted @ 2025-01-26 23:38  方韵希  阅读(30)  评论(0)    收藏  举报