二分查找

在升序中找到第一个>=key的值,同lower_bound

int lower_bound(int l,int r,int key) {
    if(a[r]<key)return r+1;

    while(l<r) {
        int m=(l+r)/2;
        if(a[m]<key)l=m+1;
        else r=m;    //a[r]>=key
    }
    return r;
}

在升序中找到第一个>key的值,同upper_bound

int upper_bound(int l,int r,int key){
    if(a[r]<=key)return r+1;

    while(l<r){
        int m=(l+r)/2;
        if(a[m]<=key)l=m+1;
        else r=m;    //a[r]>key
    }
    return r;
}

求最大化最小值或最小化最大值时,通过二分答案然后判断答案是否可行的方式求解

poj2456最大距离最小

题意:给出n个牛舍的坐标和c个牛,要求将牛放在牛舍并且使牛的距离尽量大,求最近牛的距离。
分析:二分距离d,然后判断牛是否可以按照距离d放置。

 1 #include<cstdio>
 2 #include<algorithm>
 3 using namespace std;
 4 const int maxn=1e5;
 5 
 6 int x[maxn+5];
 7 int n,c;
 8 
 9 bool check(int d){
10     int cnt=0;
11     int j=1;
12     for(int i=2;i<=n&&j<c;i++){
13         cnt+=x[i]-x[i-1];
14         if(cnt>=d)j++,cnt=0;
15     }
16     return j==c;
17 }
18 
19 int upper_bound(int l,int r){//找到最后一个可行的下一个位置
20     while(l<r){
21         int m=(l+r)/2;
22         if(check(m))l=m+1;
23         else r=m;
24     }
25     return r;
26 }
27 
28 int main(){
29     scanf("%d%d",&n,&c);
30     for(int i=1;i<=n;i++)scanf("%d",&x[i]);
31 
32     sort(x+1,x+1+n);
33     printf("%d\n",upper_bound(0,1e9)-1);
34 }
View Code

查询区间[l,r]中从左往右第一个小于key的值的下标

区间左端点固定,右端点向右移动,该区间最小值是非增序列,所以类似lower_bound来找小于key的最左边的值,其中区间最小值用rmq做到O(1)查询

 1 const int maxn=100000;
 2 
 3 int n;
 4 int a[maxn+5];
 5 int minv[maxn+5][32];
 6 
 7 void rmq(){
 8     for(int i=1;i<=n;i++)minv[i][0]=a[i];
 9 
10     for(int j=1;(1<<j)<=n;j++){
11         for(int i=1;i+(1<<j)<=n+1;i++){
12             minv[i][j]=min(minv[i][j-1],minv[i+(1<<(j-1))][j-1]);
13         }
14     }
15 }
16 
17 int query(int l,int r){
18     int k=0;
19     while((1<<(k+1))<=r-l+1)k++;
20     return min(minv[l][k],minv[r-(1<<k)+1][k]);
21 }
22 
23 int lower_bound(int l,int r,int key){//第一个小于等于key的下标
24     if(query(l,r)>key)return r+1;
25     while(l<r){
26         int m=(l+r)/2;
27         if(query(l,m)<=key)r=m;
28         else l=m+1;
29     }
30     return r;
31 }
View Code

hdu5875Function区间取模

题意:给出一个长为100000的序列,和区间[l,r]求 
分析:对比自己大的数取模等于自己,将从左向右依次取模的结果保存在ans中,然后寻找右边第一个小于等于ans的值,一个数x对小于x的值最多取模logx次就会变成0,所以复杂度为O(mlognlogn)
主程序如下:

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 
 4 int work(int l,int r){
 5     int ans=a[l];l++;
 6     while(l<=r&&ans){
 7         int k=lower_bound(l,r,ans);//第一个小于等于ans的下标
 8         if(k<=r)ans%=a[k];
 9         l=k+1;
10     }
11     return ans;
12 }
13 
14 int main(){
15     int T;scanf("%d",&T);
16     while(T--){
17         scanf("%d",&n);
18         for(int i=1;i<=n;i++)scanf("%d",&a[i]);
19         rmq();
20         int m;scanf("%d",&m);
21         while(m--){
22             int l,r;scanf("%d%d",&l,&r);
23             printf("%d\n",work(l,r));
24         }
25     }
26 }
View Code

 

posted @ 2017-04-14 18:00  poluner  阅读(173)  评论(0编辑  收藏  举报