整数二分(r=mid,l=mid+1 or l=mid r=mid-1)
bool check(int x) {/* ... */} // 检查x是否满足某种性质
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
int bsearch_1(int l, int r)
{
while (l < r)
{
int mid = l + r >> 1;
if (check(mid)) r = mid; // check()判断mid是否满足性质
else l = mid + 1; //这里一定要+1 不然最后会停在high-low=1无线循环
}
return l;
}
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
int bsearch_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;
}
eg 数的范围
给定一个按照升序排列的长度为n的整数数组,以及q个查询。
对于每个查询,返回一个元素k的起始位置和终止位置(位置从О开始计数)。
如果数组中不存在该元素,则返回-1 -1。
输入格式
第一行包含整数n和q,表示数组长度和询问个数。
第二行包含n个整数(均在1~10000范围内),表示完整数组。
接下来q行,每行包含一个整数k,表示一个询问元素。
输出格式
共q行,每行包含两个整数,表示所求元素的起始位置和终止位置。
如果数组中不存在该元素,则返回-1 -1。
#include<iostream>
using namespace std;
int list[100010];
int main(){
int n,m;
while(cin>>n>>m){
for(int i=0;i<n;i++){
cin>>list[i];
}
while(m--){
int x;
cin>>x;
// 板子
int l=0,r=n-1;
while(l<r){
int mid=r+l>>1;
if(list[mid]>=x) r=mid;
else l=mid+1;
}
if(list[l]!=x) cout<<"-1 -1"<<endl;
else{
cout<<l<<" ";
// 板子
int l=0,r=n-1;
while(l<r){
int mid=r+l+1>>1;
if(list[mid]<=x) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
}
}
先基础一点:找递增数组中大于等于x的【最小】的元素 / 小于等于x的【最大】元素
// a[]非降
// solve函数用于返回大于等于x的最【小】元素的坐标
int solve1(int x) {
int L = 1, R = n, ans = -1;
while (L < R) {
int mid = L+R>>1;
if (a[mid] >= x) { //选左
R = mid ;
}
else L = mid + 1;
}
return L;
}
// solve函数用于返回小于等于x的最【大】元素的坐标
int solve1(int x) {
int L = 1, R = n, ans = -1;
while (L < R) {
int mid = L+R>>1;
if (a[mid] <= x) { //选右
L=mid+1;
}
else R = mid ;
}
return L;
}
eg 疯牛
Aggressive cows
Description
Farmer John has built a new long barn, with N (2 <= N <= 100,000) stalls. The stalls are located along a straight line at positions x1,…,xN (0 <= xi <= 1,000,000,000).
His C (2 <= C <= N) cows don’t like this barn layout and become aggressive towards each other once put into a stall. To prevent the cows from hurting each other, FJ want to assign the cows to the stalls, such that the minimum distance between any two of them is as large as possible. What is the largest minimum distance?
Input
-
Line 1: Two space-separated integers: N and C
-
Lines 2…N+1: Line i+1 contains an integer stall location, xi
Output
- Line 1: One integer: the largest minimum distance
Sample Input 1
5 3
1
2
8
4
9
Sample Output 1
3
Hint
OUTPUT DETAILS:
FJ can put his 3 cows in the stalls at positions 1, 4 and 8, resulting in a minimum distance of 3.
题意:数轴上有固定n个点 现在要在里面选m个点,求这m个点之间的最小间隔的最大值
即max(min)
key1:二分查找【最值】 可以查出最大/最小的符合要求值(只要用ans存下就行)
key2:判断数能不能作为最小间隔 用贪心思想 逐步取点
#include<iostream>
#include<algorithm>
#include<stdio.h>
#include<string.h>
using namespace std;
const int MAX = 100010;
int a[MAX],n,m;
bool C(int d)
{
int t = a[0],count = 1;
for(int i = 1;i < n;i ++)
{
if(a[i] - t >= d)
{
count ++;
t=a[i];
if(count >= m)
return true;
}
}
return false;
}
int solve() 用二分 【查找符合条件的最大值】
{
int x = 0,y = a[n-1] - a[0],ans=0;
while(x < y) 板子
{
int mid=(x+y+1)/2;
if(C(mid))
{
x=mid ;
}
else
y=mid-1 ;
}
return x;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
for(int i = 0;i < n;i ++)
scanf("%d",&a[i]);
sort(a,a+n);
printf("%d\n",solve());
}
return 0;
}
l=mid; r=mid; 的情况下最终停在r-l==1
求递增数组中与x最接近的数
二分+递归+分奇偶
编写一个int solve(int low, int high)函数求解查找假币问题。有n(3<n<1000 000 000)个硬币,下标序号为0 ~ n-1。其中恰好有一个假币,且假币较轻,采用天平称重方式找到这个假币,函数返回假币的下标序号。
系统中提供查询函数int weigh(int x, int y),你可以用硬币的下标序号来查询任意两堆硬币在天平上的状态。返回值集合为[-1,0,1],分别表示左边重、两边相等、右边重。
weigh函数提供2个重载:
// x表示下标序号为x的硬币放在天平左边,y表示下标序号为y的硬币放在天平右边。
int weigh(int x, int y);
// x1,x2表示硬币下标序号为[x1,x2]范围内的所有硬币放在天平左边,y1,y2表示硬币下标序号为[y1,y2]范围内的所有硬币放在天平右边
int weigh(int x1, int x2, int y1, int y2);
浮点数二分 开根号
bool check(double x) {/* ... */} // 检查x是否满足某种性质
double bsearch_3(double l, double r)
{
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps)
{
double mid = (l + r) / 2;
if (check(mid)) r = mid;
else l = mid;
}
return l;
}
eg: 求立方根
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cmath>
using namespace std;
int main(){
double a;
cin>>a;
//先就考虑为正数
int flag=1;
if(a>=0) flag=1;
if(a<0){
flag=0;
a=-a;
}
double l=0,r=a+1;//范围要开大+1 因为小数根号大于自己
while(r-l>1e-8){
double mid=(l+r)/2;
if(mid*mid*mid>=a) r=mid;
else l=mid;
}
if(flag)
cout<<fixed<<setprecision(6)<<l;
if(!flag) cout<<fixed<<setprecision(6)<<"-"<<l;
}