Binary search

二分的一些判别方式

题目

给出一个长度为 \(N\) 的有序数列 \(a\)。问 \(a\) 中小于等于 \(x\) 的最大位置是多少。

判别

发现 \(a\) 有序。所以可以二分。因为二分是建立在有单调性这个基础上的。

于是,就可以得到二分的基本形式:

Code
int l=-1,r=n;
while (l+1<r){
	int mid=l+r>>1;
	if (a[mid]>x){
		r=mid;
	}
	else{
		l=mid;
	}
}

题目

(1)

abc271_c

(2)

abc236_e

判别

发现可以二分答案。这边的判别方式是 \(1.\)出现了小数(不完全);\(2.\)发现知道了答案以后判断合不合法更简单

Code for (1)
#include <bits/stdc++.h>

using namespace std;

using ll = long long;

const int N = 3e5+5;

int n;
int a[N];

bool check(int mid){
	int cnt=0;
	map<int,int> mp;
	for (int i=0; i<n; i++){
		if (a[i]<=mid && mp[a[i]]==0){
			cnt++;
			mp[a[i]]++;
		}
	}
	int nd=mid-cnt;
	nd*=2;
	return n-cnt>=nd;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n;
	for (int i=0; i<n; i++){
		cin>>a[i];
	}
	sort(a,a+n);
	int l=0,r=1e9;
	while (l+1<r){
		int mid=l+r>>1;
		if (check(mid)){
			l=mid;
		}
		else{
			r=mid;
		}
	}
	cout<<l<<endl;
	return 0;
}
Code for (2)
#include <bits/stdc++.h>

using namespace std;

#define dg(x) cout<<#x<<"="<<x<<endl

using ll = long long;
using ld = long double;

const int N = 1e5+5;
const ld eps = 10e-6;

int n;
ld a[N],b[N];
ld dp[N][2];

bool check(ll mid){
	for (int i=1; i<=n; i++){
		b[i]=(a[i]>=mid?1:-1);
	}
	dp[1][1]=b[1];
	dp[1][0]=0.00;
	for (int i=2; i<=n; i++){
		dp[i][0]=dp[i-1][1];
		dp[i][1]=max(dp[i-1][0]+b[i],dp[i-1][1]+b[i]);
	}
	return max(dp[n][0],dp[n][1])>=1.00;
}

bool chk(ld mid){
	for (int i=1; i<=n; i++){
		a[i]-=mid;
	}
	dp[1][1]=a[1];
	dp[1][0]=0.00;
	for (int i=2; i<=n; i++){
		dp[i][0]=dp[i-1][1];
		dp[i][1]=max(dp[i-1][0]+a[i],dp[i-1][1]+a[i]);
	}
	for (int i=1; i<=n; i++){
		a[i]+=mid;
	}
	return max(dp[n][0],dp[n][1])>=0.00;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0);

	cin>>n;
	for (int i=1; i<=n; i++){
		cin>>a[i];
	}
	ld L=0,R=2e9;
	while (L+eps<R){
		ld mid=(L+R)/2.000;
		if (chk(mid)){
			L=mid;
		}
		else{
			R=mid;
		}
	}
	cout<<fixed<<setprecision(10)<<L<<endl;
	ll l=0,r=2e9;
	while (l+1<r){
		ll mid=l+r>>1;
		if (check(mid)){
			l=mid;
		}
		else{
			r=mid;
		}
	}
	cout<<l<<endl;
	return 0;
}

题目

给出一个长度为 \(N\)排列 \(A\)。求 \(A\) 中有多少个区间 \([l,r]\) 使 \(\max(A_l,\cdots,A_r)=X\)

给出一个长度为 \(N\)排列 \(A\)。求 \(A\) 中有多少个区间 \([l,r]\) 使 \(\min(A_l,\cdots,A_r)=X\)

给出一个长度为 \(N\)排列 \(A\)。求 \(A\) 中有多少个区间 \([l,r]\) 使 \(\text{mex}(A_l,\cdots,A_r)=X\)

分析

发现加入一个元素,

  • \(\max,\text{mex}\) 不会变小。

  • \(\min\) 不会变大。

所以枚举 \(l\),二分 \(r\) 即可。

辨别

有一些东西的性质可以二分。

posted @ 2023-03-06 21:09  SFlyer  阅读(17)  评论(0编辑  收藏  举报