倍增及二分

倍增

原题直通车-SYGZ OJ#699. 查找位置(倍增)

题目概览

pCyhw28.png

pCyWYsH.jpg本篇对于代码风格做出的解释是:解题风格。您可能需要仔细阅读原题才可以理解。

倍增法的意思很简单:翻倍。对于所有整数,我们都可以以 2 i 2^{i} 2i + + + 2 j 2^{j} 2j + 2 . . . +2^{...} +2...来表示。

当我们判定它不在一个范围内时,就continue;否则,继续累加。

实现

#include <iostream>
#include <cmath>
#include <cstdio>
using namespace std;
int a[500010];
long long handle(int n,int k)
{
	long long t=0,p=0;
	while (1<<t<=n)
	{
		++t;
	}
	for (int i=t-1;i>=0;i--)
	{
		int delta=1<<i;
		if (p+delta>n||a[p+delta]>=k)
		{
			continue;
		}
		p+=delta;
	}
	return p+1;
}
int main()
{
    int n,m;
    scanf("%d%d",&n,&m);
    for (int i=1;i<=n;i++)
    {
    	scanf("%d",&a[i]);
	}
	for (int i=1;i<=m;i++)
	{
		int k;
		scanf("%d",&k);
		printf("%lld ",handle(n,k));
	}
    return 0;
}


pC6aTGn.png从解题的角度来说,本题还有另一种解法——二分。

二分

原题直通车-SYGZ OJ#699. 查找位置(倍增)

题目概览

pCyhw28.png

本题使用第一种二分模板——第一个值。二分即不断缩减查找范围(当然数列必须有序),时间复杂度是对数级的( O ( log ⁡ 2 n ) O(\log_{2} n) O(log2n)),能够大大缩短时间。

实现

#include <iostream>
#include <algorithm>
using namespace std;
int n,m;
int a[500010];
int binary_search(int k)
{
	int l=1,r=n;
	while (l<r)
	{
		int mid=l+r>>1;//比(l+r)/2更好
		if (a[mid]>=k)
		{
			r=mid;//查看左端是否有更小但满足条件的值
		}
		else
		{
			l=mid+1;//在右端继续查找
		}
	}
	return l;
}
int main()
{
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++)
	{
		scanf("%d",&a[i]);
	}
	for (int i=1;i<=m;i++)
	{
		int k;
		scanf("%d",&k);
		int b=binary_search(k);
		printf("%d ",b);
	}
	return 0;
}

pCyWYsH.jpg用于二分查找的序列必须是有序的。极客少年云课堂可能对此有二分模板详细解释。

参考文献

二分搜索——极客少年云课堂

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

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值