二分与双指针

一. 二分

会二分首先得会二分模板吧

1. 二分模板

typedef long long LL;   //long long 简写
LL l = 左边界,LL r = 右边界   //左右边界需自己读题分辨
while(l + 1 < r)
{
    LL mid = (l + r )>>1;                //'>>1'表示除2,与'/2'一样,只是比单纯除以2要快点
    if(check(mid))(r or l) = mid;        //左边满足条件,l = mid;
    else (l or r) = mid;                 //右边满足条件,r = mid;
}

2. 什么情况下能用到二分?(时间复杂度是O(logn))

一般用for循环遍历WA的题,可尝试用二分,说不定AC了呢!!

1.在一个有序数组中,找某个数是否存在

2.在一个有序数组中,找>=某个数最左侧的位置

3.局部最小值的问题

3. 二分使用方法

  1. 套模板

  2. 2.确定返回值(答案)是l or r;

  3. 是 l 就是 l = mid,是 r 就是 r = mid;

  4. 通过答案的范围来确定边界

  5. 写check

  6. AC

4. 例题(注重理解!!!)

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
double a,b,c,d;
int ans=0;
double f(double x)
{
	return a*x*x*x+b*x*x+c*x+d;// 计算一元三次方程的值
}
int main(){
	scanf("%lf %lf %lf %lf",&a,&b,&c,&d);
	for(int i=-100;i<100;i++){
		double l=i,r=i+1;//  找到左边界与右边界
		if(!f(l)){//   如果有满足f(x)=0的情况就输出
			printf("%.2lf ",l);
			ans++;
		}
		if(f(l)*f(r)<0){//  判断零点条件
			while(l+0.001<r){
				double mid=(l+r)/2;//  更新条件
				if(f(mid)*f(r)<=0){
					l=mid;// 左边界小了
				}
				else{
					r=mid;//  右边界大了
				}
			}
			printf("%.2lf ",r);
			ans++;
		}
		if(ans==3)break;// 只需从小到大输出满足条件的三个
	}
	return 0;
}
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=2e6+5;//注意范围
int n,k,x[maxn];
int check(ll mid)
{
	int cnt=0;//用来记录所切木头根数
	for(int i=0;i<n;i++){
		cnt+=x[i]/mid;//计算能切多少根
	}
	if(cnt>=k)return 1;//如果能满足k段木头返回真
	else return 0;//否则假
}
int main()
{
	cin>>n>>k;//读入n根木头和要得到的k段木头
	for(int i=0;i<n;i++){
		cin>>x[i];//读入每根木头的长度
	}
	ll l = 0,r = 1e8+1;//模板套用,最小边界为0(一根也切不出来),最大边界为题目所给定的
	while(l + 1 < r){
		ll mid = (l + r) >> 1;
		if(check(mid)) l = mid;//如果mid为真,说明所切的木头还可以更大
		else r = mid;//否则就减小所切长度
	}
	cout<<l<<endl;//最后输出正确结果
}
#include <stdio.h>
typedef long long ll;
const int maxn=1e6+5;
int a[maxn];
int main()
{
	int n,m;
	scanf("%d %d",&n,&m);
	for(int i=1;i<=n;i++){
		scanf("%d",&a[i]);
	}
	int x,cnt;
	for(int i=0;i<m;i++){
		scanf("%d",&x);
		ll l=1,r=n;
		while(l<r){
			ll mid=(l+r)>>1;
			if(a[mid]>=x)r=mid,cnt=mid;
			else l=mid+1,cnt=mid+1;
		}
		if(a[cnt]==x)printf("%d ",cnt);
		else printf("-1 ");
	}
}

二.双指针

相比二分,双指针我觉得比二分好理解,直接上题!

#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
const ll maxn=2e6+5;
int a[maxn],n;
int main()
{
	int t;
	cin>>t;//测试样例数
	while(t--){
		cin>>n;
		for(int i=0;i<n;i++){
			cin>>a[i];//读入每组数据
		}
		ll l=0,r=n-1;//左值为数组下标第一位,右值为数组下标最后一位
		int cnt=0,Alice=0,Bob=0,candy=0;//Alice,Bob记录各自吃到的糖果,candy记录一共吃的糖果数量
		while(l<=r){
			if(Alice<=Bob){
				Alice+=a[l];//从Alice开始吃
				l++;//吃一颗,下标往右移
				candy++;
			}
			else{
				Bob+=a[r];//糖果重量Alice>Bob时,Bob开始吃
				r--;//吃一颗,下标左移
				candy++;
			}
			if(Alice==Bob){
				cnt=max(cnt,candy);//当糖果重量相等时,就比较一次糖果数谁多,取最多糖果数
			}
		}
		cout<<cnt<<endl;//最终输出最多糖果数
	}
}

完结!!!

posted @ 2024-03-15 20:57  懒羊羊爱吃灰太狼  阅读(38)  评论(0)    收藏  举报