我对二分查找的理解是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;
}