发现以前都没有真的理解二分边界应该取多少。所以手写 $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;