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