倍增查找
写在前面的声明
这个算法是本人在补CSP-S2024 t2时偶然想到的,目前网上没有看到类似的东西,所以写下这篇文章。
如果这个东西已经被人提出来了,可以把网址放在评论区。
发明原因和具体思路
考虑现在给你一个长度为 的单调不降序列
,求序列中不大于
的数字个数。
正常来做,直接一个二分秒了对不对。
但是如果当题目复杂一点,大多数人将分不清以下这几种二分选择哪种:
int l = 0,r = n;
while(l < r){//l <= r; l < r - 1; l <= r + 1;
int mid = (l + r) >> 1;
if(check(mid)) l = mid;//l = mid + 1;
else r = mid;//r = mid - 1;
}
cout << l;//cout << r;
(图一中注释掉的代码表示其他可能的写法)
int l = 0,r = n;
int ans = 0;
while(l <= r){
int mid = (l + r) >> 1;
if(check(mid)) l = mid + 1,ans = mid;
else r = mid - 1;
}
cout << ans;
这无疑会增加思考时间和调试时间。
于是,我们的倍增查找就横空出世了。
考虑最终的答案,它在二进制下每一位要么1要么0。
类似倍增的思路,我们从大到小枚举每一位,如果答案变量的这一位为1后,当前的答案位置满足要求,就使这一位为1。否则为0。
最终复杂度为 。
优点与缺点
优点:代码容易编写,调试简单,不容易出错。并且二分能干的它都能干。
缺点:时间复杂度的常数略劣于二分。因为二分的 跑不满(常数可能
),但这个必然跑满。
总结与评价
实用性其实不高,毕竟实力稍微高一点(达到提高级),二分就算不能一次正确,也不会花太长时间调试。
不过这也是本人OI路上的一次探索,谨此留作怀念。
269

被折叠的 条评论
为什么被折叠?



