Blue---二分算法(二分查找与二分答案)

牛可乐和魔法封印

当区间具有二段性的时候就用二分来做。本题的意思就是找到数组中值为x, y区间的长度。由于是递增序列,那么必然存在二段性,直接用二分去做。唯一要注意的就是数组里可能不存在x或者y,二分查找出来的必然是>=x的最小元素与<=y的最大元素,因此分别查找出来的两个下标的元素也要算上,它们也是属于x, y的,所以区间长度的计算方式就是r-l+1。

cpp 复制代码
#include<iostream>
using namespace std;

const int N = 1e5 + 10;
int n;
int a[N];

int find1(int x)
{
    int l = 1, r = n;
    while(l < r)
    {
        int mid = l + (r - l) / 2;
        if(a[mid] >= x)
            r = mid;
        else
            l = mid + 1;
    }
    //如果元素全是小于x的就不合法了
    if(a[l] < x)
        return -1;
    return l;
}

int find2(int y)
{
    int l = 1, r = n;
    while(l < r)
    {
        int mid = l + (r - l + 1) / 2;
        if(a[mid] <= y)
            l = mid;
        else
            r = mid - 1;
    }
    if(a[l] > y)
        return -1;
    return l;
}

int main()
{
    cin >> n;
    for(int i = 1;i <= n;i++) cin >> a[i];
    int q = 0;
    cin >> q;
    while(q--)
    {
        int x = 0, y = 0;
        cin >> x >> y;
        int l = find1(x);
        int r = find2(y);
        if(l != -1 && r != -1)
            cout << r - l + 1 << endl;
        else
            cout << 0 << endl;
    }
    
    return 0;
}

P1102 A-B 数对 - 洛谷

题目的意思是找出所有满足A-B==C的序列,那移个项不就是要求我们找出所有满足等于B+C的数字个数嘛,如果序列是有序的话,并且假设B+C==2的话,那不就相当于找序列中2的个数嘛,找到2的起始位置和结束位置不就相当于找到了嘛,然后题目又说不同位置的数字一样的数对算不同的数对,因此我们统计的时候用+=叠加去统计。所以思路就出来了排序+二分。

cpp 复制代码
#include<iostream>
using namespace std;
#include<algorithm>

typedef long long LL;
LL n, c;
const int N = 2e5 + 10;
LL a[N];

//找到序列中x的个数 
int find(LL x)
{
	int l = 1, r = n;
	while(l < r)
	{
		int mid = l + (r - l) / 2;
		if(a[mid] >= x)
			r = mid;
		else
			l = mid + 1;
	}
	//由于区间里可能根本没有x,因此额外判断一下 
	int xl = 0; 
	if(a[l] != x)
		return 0;
	xl = l;
		
	l = 1, r = n;
	while(l < r)
	{
		int mid = l + (r - l + 1) / 2;
		if(a[mid] <= x)
			l = mid;
		else
			r = mid - 1;
	}
	int xr = 0;
	if(a[l] != x)
		return 0;
	xr = l;
	
	//区间长度就是x的个数 
	return xr - xl + 1;
}

int main()
{
	cin >> n >> c;
	for(int i = 1;i <= n;i++) cin >> a[i];
	sort(a + 1, a + 1 + n);	
	LL ret = 0;
	for(int i = 1;i <= n;i++)
	{
		//A = B + C
		LL A = a[i]	+ c;
		ret += find(A);
	}
	cout << ret;
	
	return 0;	
} 

P1678 烦恼的高考志愿 - 洛谷

注意:如果发生越界访问,加左右护法是一个好选择。

cpp 复制代码
#include<iostream>
using namespace std;
#include<algorithm>

typedef long long LL;
const int N = 1e5 + 10;
LL a[N];
int m, n;

//找到离x最近的两个值,返回最近的那个距离x的差值的绝对值 
LL find(LL x)
{
	//找到>=x的最小值 
	int l = 1, r = m;
	while(l < r)
	{
		int mid = l + (r - l) / 2;
		if(a[mid] >= x)
			r = mid;
		else
			l = mid + 1;
	}
	return min(abs(a[l - 1] - x), abs(a[l] - x));
}

int main()
{
	cin >> m >> n;
	for(int i = 1;i <= m;i++) cin >> a[i];
	
	sort(a + 1, a + 1 + m);
	a[0] = -1e7;
	
	LL ret = 0;
	for(int i = 1;i <= n;i++)
	{
		int x = 0;
		cin >> x;
		//x就是每一次读取进来的高考估分
		//这里有可能数值溢出 
		ret += find(x);
	} 
	cout << ret;
	
	return 0;
}

P2440 木材加工 - 洛谷

cpp 复制代码
#include<iostream>
using namespace std;
#include<algorithm>

typedef long long LL;
const int N = 1e5 + 10;
LL n, k;
LL a[N];

LL calc(LL mid)
{
	LL sum = 0;
	for(int i = 1;i <= n;i++)
	{
		//长度不够的话除完也是0 
		sum += a[i] / mid;
	}
	return sum;
}

int main()
{
	cin >> n >> k;
	for(int i = 1;i <= n;i++) cin >> a[i];
	sort(a + 1, a + 1 + n);
	LL l = 1, r = a[n];
	//这里是从左往右len在增大,获得的num在减小
	//因此这里就变成了k左边>=k,k右边<k,和博客里画的二分图正好反了 
	while(l < r)
	{
		LL mid = l + (r - l + 1) / 2;
		if(calc(mid) >= k)
			l = mid;
		else
			r = mid - 1; 
	}
    //本题相当于是查找区间中>=k的最小k所对应的最大的len
    //有可能没有满足的情况,要额外判断
	if(calc(l) >= k) 
		cout << l << endl; 
	else
		cout << 0 << endl;
	
	return 0;
}

P1873 COCI 2011/2012 #5 EKO / 砍树 - 洛谷

cpp 复制代码
#include<iostream>
using namespace std;

typedef long long LL; 
const int N = 1e6 + 10;
int n, m;
LL a[N];

LL calc(LL x)
{
	LL ret = 0;
	for(int i = 1;i <= n;i++)
	{
		if(a[i] >= x)
			ret += a[i] - x;
	}
	return ret;
}

int main()
{
	cin >> n >> m;
	for(int i = 1;i <= n;i++) cin >> a[i];
	//题目给出的树的高度是<=4e5的,所以其实可以不排序直接二分
	LL l = 1, r = 4e5 + 10;
	while(l < r)
	{
		LL mid = l + (r - l + 1) / 2;
		if(calc(mid) >= m)
			l = mid;
		else
			r = mid - 1;	
	} 
	if(calc(l) >= m)
		cout << l;
	else
		cout << 0;
		
	return 0;
}

P2678 NOIP 2015 提高组 跳石头 - 洛谷

cpp 复制代码
#include<iostream>
using namespace std;

typedef long long LL;
const int N = 5e4 + 10;
LL L, n, m;
LL a[N];

//最短跳跃距离为x时所要移走的岩石数 
//calc天然就解决了担心的a[j]-a[i]<mid直至j走到n+1
//此时算出的sum会很大,二分的时候必然会将这种情况过滤掉 
LL calc(LL x)
{
	LL sum = 0;
	LL i = 0, j = 1;
	while(j <= n + 1)
	{
		while(j <= n + 1 && a[j] - a[i] < x)
		{
			++j;
		}
		sum += j - i - 1;
		i = j;
	}
	return sum;
}

int main()
{
	cin >> L >> n >> m;
	for(int i = 1;i <= n;i++) cin >> a[i];
	//n表示起点到终点的岩石数,不包括起点和终点 
	//因此还需要更新n到n+1两块岩石之间的距离
	//0~1这两块岩石间的距离就是a[1],所以不用去管了
	a[n+1] = L;
	
	LL l = 1, r = L;
	while(l < r) 
	{
		LL mid = l + (r - l + 1) / 2;
		if(calc(mid) <= m)
			l = mid;
		else 
			r = mid - 1;
	}
	if(calc(l) <= m)
		cout << l << endl;
	
	return 0;
} 
相关推荐
长河1 小时前
Java的GC(垃圾回收)中,标记无用对象的核心方法是可达性分析算法
java·jvm·算法
月光船幽幽2 小时前
加性偏移外推提升参数识别可靠性
python·算法
Ivanqhz2 小时前
层归一化、残差、前馈网络与激活函数简述
服务器·数据库·人工智能·深度学习·算法
不会就选b3 小时前
算法日常・每日刷题--<动态规划>3
数据结构·算法
-dzk-4 小时前
【堆】LC 347.前 K 个高频元素
算法·堆
H.莓飛4 小时前
【数据结构】栈_OJ题
linux·数据结构·算法·centos
Zootopia6264 小时前
多架 eVTOL集群排班调度方案思考
人工智能·算法·数学建模·matlab·动态规划·无人机·evtol
和裕4 小时前
年度框架直供 vs 零散按需采购:定制纸箱采购成本、交付与服务核心区别全对比
大数据·运维·网络·人工智能·算法
朝朝辞暮i4 小时前
C++ 第 13 课:值传递 —— 为什么函数里改了,外面却没变?
java·c++·算法