二分模板

我的二分学习极度坎坷,到了现在(大二),遇到二分题,立马跑路,,感觉自己好憨批(看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;
}

冲冲冲!快考试了,不能拉下!

posted @ 2020-11-25 09:21  ACHanHan  阅读(130)  评论(2编辑  收藏  举报