本讲内容分为两个部分;
第1部分:二分答案介绍
第2部分:整体二分介绍
Part 1 二分答案介绍
相信大家都对二分答案比较熟悉。
至少...需要会二分查找...
我们考虑对于决策单调的问题:
给出一个长度为$n$的递增数列,现在有$m$个询问,每个询问有一个参数$k_i$
对于每一个询问输出这个递增序列中的大于等于$k_i$的位置最靠前的项的位置。
如果没有输出$-1$
对于100%的数据$ n,m \leq 10^6$
这个就大概是二分查找的模板题了,我们当考虑的是当前搜区间是$[L,R]$
其中间项$M=\left \lfloor \frac{L+R}{2} \right \rfloor$大于还是小于$k_i$
如果严格$a_M \geq k_i$,那么搜$[L,M]$否则搜$[M+1,R]$
显然这段代码就可以干这件事情
# include <bits/stdc++.h> using namespace std; const int N=1e6+10; int a[N],n,m; int work(int k) { int l=1,r=n,ans=-1; while (l<=r) { int m=(l+r)/2; if (a[m]>=k) r=m-1,ans=m; else l=m+1; } return ans; } int main() { scanf("%d%d",&n,&m); for (int i=1;i<=n;i++) scanf("%d",&a[i]); while (m--) { int k; scanf("%d",&k); printf("%d\n",work(k)); } return 0; }
不作赘述。
满足决策单调性的事情可以用二分答案转化为判定类问题。
给出二分答案模板:
int l=-inf,r=inf,ans; while (l<=r) { int mid=(l+r)>>1; if (check(mid)) ans=mid,l=mid+1; //向更优解尝试 else r=mid-1; //向更劣解尝试 } return ans;
然而今天的重点不是这个,这个有点low