二分查找——模板,AcWing789题 卖古董 洛谷切绳子

AcWing789题

给定一个按照升序排列的长度为n的整数数组,以及 q 个查询。

对于每个查询,返回一个元素k的起始位置和终止位置(位置从0开始计数)。

如果数组中不存在该元素,则返回“-1 -1”。

输入格式

第一行包含整数n和q,表示数组长度和询问个数。

第二行包含n个整数(均在1~10000范围内),表示完整数组。

接下来q行,每行包含一个整数k,表示一个询问元素。

输出格式

共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回“-1 -1”。

数据范围

1≤n≤100000
1≤q≤10000
1≤k≤10000

输入样例:

6 3
1 2 2 3 3 4
3
4
5

输出样例:

3 4
5 5
-1 -1

#include <bits/stdc++.h>

using namespace std;

const int N=1e5+5;

int main() {
    
    
    int arr[N],n,q,k,l,r,mid;
    scanf("%d%d",&n,&q);
    for (int i = 0; i < n; ++i)  scanf("%d",arr+i);
    while (q--){
    
    
        scanf("%d",&k);
        l=0,r=n-1;
        while (l<r){
    
    //找右半部分,满足性质a[i]>=x的最小位置
            mid=l+r>>1;
            if(arr[mid]>=k)  r=mid;
            else l=mid+1;
        }
        if(arr[l]!=k) printf("-1 -1\n");//如果数组中不存在这样数,到下标n-1就会停止,需要判断
        else{
    
    
            printf("%d ",l);
            l=0,r=n-1;
            while (l<r){
    
    //找左半部分,满足性质a[i]<=x的最大位置
                mid=l+r+1>>1;
                if (arr[mid]<=k) l=mid;
                else r=mid-1;
            }
            printf("%d\n",l);
        }

    }

    return 0;
}

卖古董 Problem1211

你的朋友小明有n个古董,每个古董的价值给出,然后小明要在接下来的m天内将所有古董依次卖出(注意:必须依次卖出,也就是从第一个开始卖卖到最后一个),小明希望的是这m天内每天卖出的价值和的最大值最小,你来帮助他吗?

输入格式

一共T组数据,每组一个n和m,代表n个古董以及m天(1<=m<=n),然后下面n行为古董的价值,古董价值为1到10000(1<=n<=100000)

输出格式

输出m天内卖出的古董价值和的最大值(当然是最优的时候),我们希望的是这个最大值越小越好

输入样例

3
7 5
100
400
300
100
500
101
400
4 3
2
6
2
4
4 2
2
6
2
4

输出样例

500
6
8

提示

分成几段 {100,400}{300,100},{500},{101}{400};这里分成了5段; 每段都 <=500;
500是很多成功分段方案中,每段的最大值当中最小的一组;

#include <bits/stdc++.h>

using namespace std;

const int N=100010;
int q[N],n,m;

bool check(int dollar)
{
    
    
    bool tag= false;
    int temp=dollar,day=1;//day记录分成的天数,默认第一个就是第一天卖的第一件古董。
    for (int i = 0; i < n;) {
    
    
        if(temp<q[i])   {
    
     day++,temp=dollar;}//此时q[i]就是下一天卖的第一件物品
        else temp-=q[i++];
    }
    if(day<=m) tag= true;//我们希望找出右半部分,mid的最小值满足day<=m
    return tag;
}

int main() {
    
    
    int T,max,sum;
    cin>>T;
    while(T--){
    
    
        scanf("%d%d",&n,&m);
        max=-1,sum=0;
        for (int i = 0; i < n; ++i){
    
    
            scanf("%d",q+i);
            if(max<q[i])  max=q[i];
            sum+=q[i];
        }
        int l=max,r=sum;
        while (l<r){
    
    
            int mid=l+r>>1;
            if (check(mid)) r=mid;
            else l=mid+1;
        }
        printf("%d\n",l);
    }

    return 0;
}

小清新切绳子-二分 Problem1648

洛谷切绳子整数版

#include <bits/stdc++.h>

using namespace std;

typedef long l;
int Li[10005],K,n;

bool check(int len)
{
    
    
    bool tag=false;
    l k=0;  //怕k超出范围,用long类型
    for (int i = 0; i < n; ++i)   k+=Li[i]/len;
    if(k>=K)  tag=true; //为1说明满足要求 为0不满足要求
    return tag;      //我们要求满足要求下的最大值len
}//为了快点或者节省空间,用bool类型

int main()
{
    
    
    l max,sum;
    while (~scanf("%d%d",&n,&K))
    {
    
    
        max=-1,sum=0;
        for (int i = 0; i < n; ++i) {
    
    
            scanf("%d",Li+i);
            if (max<Li[i]) max=Li[i];
            sum+=Li[i];
        }
        int l=max/K,r=sum/K;//避免太盲目 自己先给定最可能的区间
        while (l<r){
    
    
            int mid=l+r+1>>1;
            if (check(mid))  l=mid;
            else r=mid-1;
        }
        printf("%d\n",r);
    }
    return 0;
}

模板

整数二分

一、区间[l,r]被划分成[l,mid] [mid+1,r]时使用
适用情况:右半部分,求>=x的最小数时使用

int search_1(int l,int r)
{
    
    
    while(l<r){
    
    
        int mid=l+r>>1;
        if(check(mid))  r=mid;
        else l=mid+1;
    }
    return l; //return r;都行
}

二、区间[l,r]被划分成[l,mid-1] [mid,r]时使用
适用情况:左半部分,求<=x的最大数时使用

int search_2(int l,int r)
{
    
    
    while(l<r){
    
    
        int mid=l+r+1>>1;
        if(check(mid)) l=mid;
        else r=mid-1;
    }
    return l;
}

实数二分

double search(double l,double r)
{
    
    
    while(r-l>0.0000001)//一个误差,或者直接写成for(int i=0;i<n;++i)
    {
    
                                     //不管三七二十一,循环n次结束
        double mid=(r+l)/2;
        if(check(mid))  r=mid;//l=mid;
        else l=mid;//r=mid;
    }
    return l;
}

猜你喜欢

转载自blog.csdn.net/HangHug_L/article/details/112690121