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)
(2)
判别
发现可以二分答案。这边的判别方式是 \(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\) 即可。
辨别
有一些东西的性质可以二分。