第二周周报:预备队训练-week2(二分查找)

我对二分查找的理解是check作为两个部分的分界线,最终L停留在分界线左侧,R停留在分界线右侧。再根据题目取需要的L/R即可。

P1102 A-B 数对

题目背景

出题是一件痛苦的事情!

相同的题目看多了也会有审美疲劳,于是我舍弃了大家所熟悉的 A+B Problem,改用 A-B 了哈哈!

题目描述

给出一串正整数数列以及一个正整数 CC,要求计算出所有满足 A - B = CA−B=C 的数对的个数(不同位置的数字一样的数对算不同的数对)。

输入格式

输入共两行。

第一行,两个正整数 N,CN,C。

第二行,NN 个正整数,作为要求处理的那串数。

输出格式

一行,表示该串正整数中包含的满足 A - B = CA−B=C 的数对的个数。
#include <bits/stdc++.h>
using namespace std;
int P[1008611],N,C,flag1,B,L,R,mid,num,flag2;
long long h;
int main()
{
    cin>>N>>C;
    for(int i=1;i<=N;i++)cin>>P[i];
    sort(P+1,P+N+1);
    for(int i=1;i<=N;i++)
    {
        L=lower_bound(P+1,P+N+1,P[i]+C)-&P[1];//把所有元素看作A,在数组中寻找B的首位置
        R=upper_bound(P+1,P+N+1,P[i]+C)-&P[1];//寻找B的末位置
        h+=R-L;//
    }
    cout<<h;
}

P1873 [COCI 2011/2012 #5] EKO / 砍树

题目描述

伐木工人 Mirko 需要砍 MM 米长的木材。对 Mirko 来说这是很简单的工作,因为他有一个漂亮的新伐木机,可以如野火一般砍伐森林。不过,Mirko 只被允许砍伐一排树。

Mirko 的伐木机工作流程如下:Mirko 设置一个高度参数 HH(米),伐木机升起一个巨大的锯片到高度 HH,并锯掉所有树比 HH 高的部分(当然,树木不高于 HH 米的部分保持不变)。Mirko 就得到树木被锯下的部分。例如,如果一排树的高度分别为 20,15,1020,15,10 和 1717,Mirko 把锯片升到 1515 米的高度,切割后树木剩下的高度将是 15,15,1015,15,10 和 1515,而 Mirko 将从第 11 棵树得到 55 米,从第 44 棵树得到 22 米,共得到 77 米木材。

Mirko 非常关注生态保护,所以他不会砍掉过多的木材。这也是他尽可能高地设定伐木机锯片的原因。请帮助 Mirko 找到伐木机锯片的最大的整数高度 HH,使得他能得到的木材至少为 MM 米。换句话说,如果再升高 11 米,他将得不到 MM 米木材。

输入格式

第 11 行 22 个整数 NN 和 MM,NN 表示树木的数量,MM 表示需要的木材总长度。

第 22 行 NN 个整数表示每棵树的高度。

输出格式

11 个整数,表示锯片的最高高度。 

#include <algorithm>
#include <bits/stdc++.h>
using namespace std;
long long P[1008611],N,C,flag1,B,L,R,mid,num,flag2;
long long l,r;//int小了不能ac
int check(int n)
{
    num=0;
    for(long long i=1;i<=N;i++)
    {
        if(P[i]<=n)num+=0;
        else num+=P[i]-n;
    }
    if(num>=L)return 1;
    else return 0;
}
int main()
{
    cin>>N>>L;
    for(long long i=1;i<=N;i++)cin>>P[i];
    sort(P+1,P+N+1);
    l=0,r=P[N]+1;//边界(0,P[N]+1)
    while(l+1!=r)//答案二分
    {
        mid=(l+r)>>1;
        if(check(mid))l=mid;//[1,L]满足木材数量>=M米,则R正好是使得木材数<M米的第一个数
        else r=mid;
    }
    cout<<l;
   
}

P1824 进击的奶牛

题目描述

Farmer John 建造了一个有 NN(22 \le≤ NN \le≤ 100000100000) 个隔间的牛棚,这些隔间分布在一条直线上,坐标是 x_1x1​ ,...,x_NxN​ (0 \le≤ x_ixi​ \le≤ 10000000001000000000)。

他的 CC(22 \le≤ CC \le≤ NN) 头牛不满于隔间的位置分布,它们为牛棚里其他的牛的存在而愤怒。为了防止牛之间的互相打斗,Farmer John 想把这些牛安置在指定的隔间,所有牛中相邻两头的最近距离越大越好。那么,这个最大的最近距离是多少呢?

输入格式

第 11 行:两个用空格隔开的数字 NN 和 CC。

第 22 ~ N+1N+1 行:每行一个整数,表示每个隔间的坐标。

输出格式

输出只有一行,即相邻两头牛最大的最近距离。

 #include <bits/stdc++.h>
using namespace std;
int A[1008611],B[1008611],l,r,mid,L,R,MID,n,m;
int check(int N)
{
    int num=1;
    for(int i=1;i<=n;i++)//二分查找下一个符合条件的牛棚
    {
        L=i-1,R=n+1;
        while(L+1!=R)
        {
            MID=(L+R)/2;
            if(A[MID]-A[i]>=N)L=MID;
            else R=MID;
        }
        if(A[L]-A[i]>=N)num++;
        i=L-1;//for循环结束后i++l,故-1为敬(这个bug我修了半个小时)
    }
    //cout<<num<<endl;
    if(num>=m)return 1;
    else return 0;
}
int main() 
{
   cin>>n>>m;
   for(int i=1;i<=n;i++)cin>>A[i];
   sort(A+1,A+n);
   l=0,r=A[n]-A[1]+1;
   while(l+1!=r)//答案二分
   {
       mid=(l+r)/2;
       //cout<<"mid="<<mid<<endl;
       if(check(mid))l=mid;
       else r=mid;
       //cout<<"l="<<l<<"   "<<"r="<<r<<endl;
   }
    if(check(r))cout<<r;
    else cout<<l;
       //cout<<"l="<<l<<"   "<<"r="<<r<<endl;
}

P2249 【深基13.例1】查找

题目描述

输入 nn 个不超过 10^9109 的单调不减的(就是后面的数字不小于前面的数字)非负整数 a_1,a_2,\dots,a_{n}a1​,a2​,…,an​,然后进行 mm 次询问。对于每次询问,给出一个整数 qq,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1−1 。

输入格式

第一行 22 个整数 nn 和 mm,表示数字个数和询问次数。

第二行 nn 个整数,表示这些待查询的数字。

第三行 mm 个整数,表示询问这些数字的编号,从 11 开始编号。

输出格式

输出一行,mm 个整数,以空格隔开,表示答案。

#include <bits/stdc++.h>
using namespace std;
int A[1008611],B[1008611],l,r,mid;
int main() 
{
   int n,m;
   cin>>n>>m;
   for(int i=1;i<=n;i++)cin>>A[i];
   for(int i=1;i<=m;i++)cin>>B[i];
   sort(A+1,A+n+1);
   for(int i=1;i<=m;i++)
   {
       l=0,r=n+1;
       while(l+1!=r)
       {
           mid=(l+r)/2;
           if(A[mid]>=B[i])r=mid;
           else l=mid;
       }
       //cout<<"l="<<l<<"   "<<"r="<<r<<endl;
       if(A[r]!=B[i])cout<<"-1";
       else cout<<r;
       if(i!=m)cout<<" ";
   }
}
 

P2678 [NOIP2015 提高组] 跳石头

题目背景

一年一度的“跳石头”比赛又要开始了!

题目描述

这项比赛将在一条笔直的河道中进行,河道中分布着一些巨大岩石。组委会已经选择好了两块岩石作为比赛起点和终点。在起点和终点之间,有 NN 块岩石(不含起点和终点的岩石)。在比赛过程中,选手们将从起点出发,每一步跳向相邻的岩石,直至到达终点。

为了提高比赛难度,组委会计划移走一些岩石,使得选手们在比赛过程中的最短跳跃距离尽可能长。由于预算限制,组委会至多从起点和终点之间移走 MM 块岩石(不能移走起点和终点的岩石)。

输入格式

第一行包含三个整数 L,N,ML,N,M,分别表示起点到终点的距离,起点和终点之间的岩石数,以及组委会至多移走的岩石数。保证 L \geq 1L≥1 且 N \geq M \geq 0N≥M≥0。

接下来 NN 行,每行一个整数,第 ii 行的整数 D_i( 0 < D_i < L)Di​(0<Di​<L), 表示第 ii 块岩石与起点的距离。这些岩石按与起点距离从小到大的顺序给出,且不会有两个岩石出现在同一个位置。

输出格式

一个整数,即最短跳跃距离的最大值。

#include <bits/stdc++.h>
using namespace std;
int A[1008611],B[1008611],l,r,mid,L,R,MID,n,m,YICHU;
int check(int N)
{
    int num=0;
    L=0;
    for(int i=1;i<=m+1;i++)//挨个查找
    {
        if(A[i]-A[L]<N)num++;
        else L=i;
        /*如果相邻的石头间距小于N,num++,此时忽略第i块石头,即此时L仍然是i-1,转为计算i-1与i+1的间距*/
    }
    //cout<<"num="<<num<<"N="<<N<<endl;
    if(num>YICHU)return 0;//如果移除的石头数量num大于题目所给的最大移除数量
    else return 1;
}
int main() 
{
   cin>>n>>m>>YICHU;
   if(m==0&&m<=YICHU)
   {
       cout<<n;
       return 0;
   }
   for(int i=1;i<=m;i++)cin>>A[i];
   A[m+1]=n;
   sort(A+1,A+m+1);
   l=0,r=n+1;
   while(l+1!=r)//答案二分
   {
       mid=(l+r)/2;
      // cout<<"mid="<<mid<<endl;
       if(check(mid))l=mid;//相当于check是一条线,线左侧是l,右侧是r
       else r=mid;
       //cout<<"l="<<l<<"   "<<"r="<<r<<endl;
   }
    if(check(r))cout<<r;
    else cout<<l;
       //cout<<"l="<<l<<"   "<<"r="<<r<<endl;
}
 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值