基本技巧(长期更新)

贪心

贪心总结

分治

分治总结

二分

看到使最大值最小或者使最小值最大时都可以尝试上二分。

注意二分的问题要有单调性(在某一点之前都不满足,之后都满足)。

二分的n种写法

虽然令人难蚌,但二分有很多种写法,尽量都了解/掌握。

虽然说是很多种写法但还是就记录主流的吧QwQ

第一种:

个人认为最好写最好理解的一种

在单调递增序列a中查找第一个大于等于x的值的位置。

区间为[l,r],最终答案为ans

\\初始化l,r,并且ans=-1

while(l<=r){
  int mid=l+r>>1;
  if(a[mid]>=x) ans=mid,r=mid-1;//l=mid+1或者r=mid-1,根据题目和自己写的check判断。
  else l=mid+1;
}

\\最后得到的ans即为答案,如果ans=-1则无解

第二种:

分为两套。答案都处于[l,r]中,循环以l=r结束,每次二分的中间值mid属于左右两段之一。

  1. 在单调递增序列a中查找第一个大于等于x的值的位置(xx的后继)。
while(l<r){
  int mid=l+r>>1;
  if(a[mid]>=x) r=mid;
  else l=mid+1;
}

//最终l即为答案
  1. 在单调递增序列a中查找最后一个小于等于x的值的位置(xx的前驱)。
while(l<r){
  int mid=l+r+1>>1;
  if(a[mid]<=x) l=mid;
  else r=mid-1;
}

//最终l即为答案

总结一下两种形式:

  1. 缩小范围时,r=mid,l=mid+1,取中间值时,mid=l+r1

  2. 缩小范围时,l=mid,r=mid1,取中间值时,mid=l+r+11

接下来说明2中对mid的取法作区分是必须的。

假如2中同样采用mid=l+r1,那么当rl=1时,mid=l+r1=l,此时如果l=mid,区间未缩小;如果r=mid1,造成l>r,循环不能以l=r结束。因此是必须的。

注意必须采用而非/,这是因为向下取整,而/向零取整,当[l,r]含负数时后者无法正常工作。

特别的作用:我们观察一下,mid=l+r1取不到rmid=l+r+11取不到l,可以借此处理无解的情况。将最初的区间向左/向右拓宽一位,包含一个越界的下标。如果最后的答案停留在这个越界的下标上,就说明无解。

终止时l=r,若有解,此处便是答案。

实数域上二分

比整数域上的简单多了

首先要确定二分精度eps,以l+eps<r为循环条件,每次依据mid处的判定选择l=mid或者r=mid分支之一即可。

一般来说,要保留k位小数时,设置eps=10(k+2)

注意此时就只能使用/了。

while(l+eps<r){
  double mid=(l+r)/2;
  if(check(mid)) l=mid;
  else r=mid;
}

也可以用固定循环次数的二分,精度通常比设置eps高。

for(int i=0;i<100;++i){
  double mid=(l+r)/2;
  if(check(mid)) l=mid;
  else r=mid;
}

二分的重要思想

最优化问题也能抽象为函数。

要二分答案,函数就要有单调性,即在一边都不合法,一边都合法。

求最优解的问题转化为判定是否能构造出解为mid的方案。

wqs二分

去看DP优化。

倍增

前缀和与差分

启发式搜索和迭代加深

DLX

posted @   RandomShuffle  阅读(12)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 无需6万激活码!GitHub神秘组织3小时极速复刻Manus,手把手教你使用OpenManus搭建本
· Manus爆火,是硬核还是营销?
· 终于写完轮子一部分:tcp代理 了,记录一下
· 别再用vector<bool>了!Google高级工程师:这可能是STL最大的设计失误
· 单元测试从入门到精通
点击右上角即可分享
微信分享提示