【二分查找】

【二分查找】

二分模版

如果二分出来有问题,一定不会是模版的问题!

/*
若R=mid L=mid+1->找满足条件更小的->(L+R)>>1
若L=mid R=mid-1->找满足条件更大的->(L+R+1)>>1
答案就是L/R
*/
int L=0,R=INF;
while(L<R){
	int mid=(L+R)>>1;
	if(check(mid)) R=mid;
	else L=mid+1;
}
int ans=L;

注意l和r的边界问题!!!

STL中的二分查找

只要是有序序列都可以使用:vector、set、multiset

//首个*大于等于*给定值的元素的函数
lower_bound(first,last,val)
//首个*大于*给定值的元素的函数
upper_bound(first,last,val)
//一般都是返回位置 需要加*

//如果需要找小于/小于等于的最大?传cmp即可
bool cmp(const int &a,const int &b) { return a > b; }
int *p1=lower_bound(a+1,a+n+1,k,cmp);

题目积累

Skibidus and Fanum Tax (hard version)

https://codeforces.com/contest/2065/problem/C2

思路

遍历a数组,依次确定每个数
在b数组里二分找大于前一个已经确定的数的b[j]-a[i](记得先排序)
判无解
(1)找不到b->b边界到最右边(注意手写二分时的边界问题)
(2)a[i]也小于res
特别的:a[1]要尽量小->b[1]也要尽量小

代码

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=2e5+10;
const ll INF=0x3f3f3f3f;
int t;
int n,m;
ll a[N],b[N];
void solve(){
      cin>>n>>m;
      memset(a,0,sizeof a);
      memset(b,0,sizeof b);
      for(int i=1;i<=n;i++) cin>>a[i];
      for(int i=1;i<=m;i++) cin>>b[i];
      sort(b+1,b+1+m);
      if(n==1) cout<<"YES"<<endl;
      else{
            ll res=0;
            res=min_(a[1],b[1]-a[1]);
            bool is_ok=true;
            for(int i=2;i<=n;i++){
                  //二分判无解:坐标在第一个/最后一个(注意l和r的区间!!!)
                  int l=1,r=m+1;
                  while(l<r){
                        int mid=(l+r)>>1;
                        if((b[mid]-a[i])>=res) r=mid;//二分一个修改后大于等于某数的最小值
                        else l=mid+1;
                  }
                  ll tmp=INF;
                  if(l!=m+1) tmp=min_(tmp,b[l]-a[i]);
                  if(a[i]>=res) tmp=min_(tmp,a[i]);
                  if(tmp==INF){
                        is_ok=false;
                        break;
                  }
                  res=tmp;
            }
            if(is_ok) cout<<"YES"<<endl;
            else cout<<"NO"<<endl;
      }
}
signed main(){
      ios::sync_with_stdio(0);
      cin.tie(0);
      cout.tie(0);
      cin>>t;
      while(t--) solve();
      return 0;
}

Circle Perimeter

【边界问题】什么情况是找不到的?
https://codeforces.com/contest/1971/problem/F

#include<bits/stdc++.h>
using namespace std;
#define endl '\n'
typedef pair<int,int> PII;
typedef long long ll;
ll abss(ll a){return a>0?a:-a;}
ll max_(ll a,ll b){return a>b?a:b;}
ll min_(ll a,ll b){return a<b?a:b;}
bool cmpll(ll a,ll b){return a>b;}
const int N=1e5+10;
ll x;
void solve(){
    cin>>x;
    ll ans=0;
    //找左右边界即可 角点单独判断:注意边界问题
    for(ll i=1;i<=x;i++){
        //找左端点
        //什么情况是找不到的?找到的点>=i
        ll l=1,r=N;
        while(l<r){
            ll mid=(l+r)>>1;
            ll tmp=(i*i+mid*mid);
            if(tmp>=x*x) r=mid;
            else l=mid+1;
        }
        ll cnt1=l;
        //cout<<cnt1<<" ";
        if(cnt1<i && cnt1>=1){
            l=1,r=N;
            while(l<r){
                ll mid=(l+r+1)>>1;
                ll tmp=(i*i+mid*mid);
                if(tmp<(x+1)*(x+1)) l=mid;
                else r=mid-1;
            }
            ll cnt2=l;
            //cout<<cnt2;
            if((i*i+cnt2*cnt2)>=x*x){
                if(cnt2<1) continue;
                else if(cnt2>=i) cnt2=i-1;
                ll res=cnt2-cnt1+1;
                ans+=res;
            }
        }
    }
    ans*=8;
    ans+=4;
    ll L=0,R=x;
    while(L<R){
        ll mid=(L+R)>>1;
        if(mid*mid*2>=x*x) R=mid;
        else L=mid+1;
    }
    if(L*L*2<(x+1)*(x+1) && L*L*2>=x*x) ans+=4;
    cout<<ans<<endl;
}

signed main(){
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    int T;
    cin>>T;
    while(T--) solve();
    return 0;
}
posted @ 2025-01-11 14:56  White_ink  阅读(9)  评论(0)    收藏  举报