二分的边界与答案的初始化
发现以前都没有真的理解二分边界应该取多少。所以手写 $lower_bound$ 出了一些锅,于是用了3种不同方式拍了几组数据改了下错,才真正理解了。
先上对拍程序(windows)
$mian.cpp$
#include<bits/stdc++.h>
#include<windows.h>
using namespace std;
#define LL long long
#define file(a) freopen(#a".in","r",stdin),freopen(#a".out","w",stdout)
inline int read(){
int s=0,f=1;char ch=getchar();
while(ch<'0'||'9'<ch) {if(ch=='-') f=-1;ch=getchar();}
while('0'<=ch&&ch<='9') {s=s*10+(ch^48);ch=getchar();}
return s*f;
}
const int N=10000;
int n,k;
int a[N];
int ans1,ans2,ans3;
int main(){
int Q=1000;
while(Q--){
system("start D:/...省略.../data.exe");
freopen("data.in","r",stdin);
n=read();k=read();
for(int i=1;i<=n;++i){
a[i]=read();
}
sort(a+1,a+1+n);
ans1=lower_bound(a+1,a+1+n,k)-a-1;
int l=1,r=n;ans2=n+1;
while(l<=r){
int mid=(l+r)>>1;
if(a[mid]>=k)
ans2=mid,r=mid-1;
else l=mid+1;
}
--ans2;
l=1,r=n;ans3=0;
while(l<=r){
int mid=(l+r)>>1;
if(a[mid]<k)
ans3=mid,l=mid+1;
else r=mid-1;
}
printf("%d %d %d\n",ans1,ans2,ans3);
if(ans1!=ans2||ans1!=ans3||ans2!=ans3){
printf("Error!\n");
printf("%d %d\n",n,k);
for(int i=1;i<=n;++i){
printf("%d ",a[i]);
}
return 0;
}
fclose(stdin);
Sleep(1000);
}
return 0;
}
$data.cpp$
#include<bits/stdc++.h>
using namespace std;
int main(){
freopen("data.in","w",stdout);
srand(time(0));
mt19937 read(rand());
int n=read()%20+1,k=read()%1000+1;
printf("%d %d\n",n,k);
for(int i=1;i<=n;++i){
printf("%d ",read()%1000+1);
}
putchar('\n');
fclose(stdout);
return 0;
}
对于只有一个点的情况,如果左右边界选大会出错误答案,同时如果是方法 $2$,我们 $ans$ 初始值设为 $0$ 也是会有问题的,因为如果所有值都比标准值 $k$ 小,那么不会更新 $ans$,所以 $ans$ 初始值要设为 $n$。
总结
二分的时候,应该: $l$ 和 $r$ 贴紧左右区间,然后 $ans$ 设为如果不更新时的答案。
然后浮点数二分的时候,我们参考这个
LD l=0,r=pi;
while(l+exps<r){
LD mid=(l+r)*0.5;
if(check(tan(mid) )<key) l=mid;
else r=mid;
}
return l;