倍增
题目概览
本篇对于代码风格做出的解释是:解题风格。您可能需要仔细阅读原题才可以理解。
倍增法的意思很简单:翻倍。对于所有整数,我们都可以以 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;
}
从解题的角度来说,本题还有另一种解法——二分。
二分
题目概览
本题使用第一种二分模板——第一个值。二分即不断缩减查找范围(当然数列必须有序),时间复杂度是对数级的( 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;
}
用于二分查找的序列必须是有序的。极客少年云课堂可能对此有二分模板详细解释。