二分模板
我的二分学习极度坎坷,到了现在(大二),遇到二分题,立马跑路,,感觉自己好憨批(看y总板子背不过)。
最后还是dalao拯救了我,呜呜呜,感动。dalao板子太强了!
感激!感激!这次我一定要学会,妈妈再也不用担心我不会二分找答案了。
二分可以解决的问题:找到满足条件的极限值。必须是极限值的一端一定不符合条件(不可以选择),另一端符合 条件
二分板子:(理解+记忆) 淦!
找满足条件最小值:找最小的满足的值(大的都满足),所以找的是正确的r,所以输出的是r。
//假设答案可能的范围是 1到n
int l=1,r=n;
while(l<r){
int mid=(l+r)>>1;//中间指针
if(check(mid)) r=mid;//如果中间的值满足,那么减小r来缩小范围
else l=mid+1;//否则,增大l,尽量让mid满足。
}
cout<<r<<endl;//此时的r即为正确答案。
找满足条件的最大值:找的是满足条件的最大值(小的都满足条件),所以找的是正确的l,所以输出与l有关。
//假设答案可能的范围是 1到n
int l=2,r=n+1;
while(l<r){
int mid=(l+r)>>1;
if(check(mid)) l=mid+1;
else r=mid;
}
cout<<l-1<<endl;//因为不断更新l的值的时候是让l变成mid+1(此时是mid满足)
例题:
1385 C. Make It Good(二分!!!)
题目链接:https://codeforces.com/contest/1385/problem/C
题目大意:选择删除前缀几个数字,使得剩下的数字可以选择他的第一个数或者最后一个数,选择的数必须比上次选择的数字小或相等,问最少删除几个前缀数字可以成立。
样例解释:
第一个样例不需要删除,每次选择第一个数字即可。
第二个样例需要删除前4个数字:得到 4 5 2 -> 选最后一个 2 -> 选第一个数4 -> 选第一个数 5 得到2 4 5 是非递减的顺序。
....
解题思路:
删除的前边的数字越多,得到的数组肯定符合,所以要找最小的满足条件的数字n,既可以想到二分。
使用dalao的第一个板子移动r找最小值即可。
AC代码:
#include <iostream>
using namespace std;
const int maxn = 2e5+5;
int a[maxn];
int n;
bool check(int x){//从 x位置开始放
int l=x,r=n-1;
int now;
if(a[l]<a[r]){
now=a[l];
l++;
}else{
now=a[r];
r--;
}
while(l<=r){//看选择最左边的数还是最右边的数
if(a[l]>=now&&a[r]>=now){//如果都小于上一个数,贪心思想,选择最小的
if(a[l]<a[r]){
now=a[l];
l++;
}else{
now=a[r];
r--;
}
}else if(a[l]>=now){//只能选择左边的情况
now=a[l];
l++;
}else if(a[r]>=now){//只能选择右边的情况
now=a[r];
r--;
}else{
return false;
}
}
return true;
}
int main(){
int t;
cin>>t;
while(t--){
cin>>n;//找的最小的
for(int i=0;i<n;i++){
cin>>a[i];
}
int l=0,r=n-1;
while(l<r){//二分答案
int mid=(l+r)/2;
if(check(mid)) r=mid;
else l=mid+1;
}
printf("%d\n",r);
}
return 0;
}
冲冲冲!快考试了,不能拉下!