二分算法的总结
模板
说到算法肯定要说到模板对吧:
最小值:
int l=1,r=n,mid;
while(r>l){
mid=l+r>>1;
if(check(mid))r=mid;
else l=mid+1;
}
return r;
最大值:
int l=1,r=n,mid;
while(r>l){
mid=l+r>>1
if(check(mid))l=mid;
else r=mid-1;
}
return l;
原理解析:
核心代码:
if(check(mid))r=mid; //1
else l=mid+1; //2
or
if(check(mid))l=mid;
else r=mid-1;
结合此图感性理解:
为什么会正确的呢?
这也是二分算法的难点 虽然很简单
当mid
合法时,他会被l
或者r
记录下来
在此对l-mid或者mid-r进行同样的操作,一直到区间不合法为止
模板清楚了,来练几道题
1.模板题
很简单的一道题
第一步:先找到k
的范围
第二步:其次通过坐标-1
或+1
找出连续的数起始位置和终止位置
code:
#include<bits/stdc++.h>
using namespace std;
int a[10000],n;
inline void find(int k){
int l=1,r=n,mid;
while(r>l){
mid=l+r>>1;
if(a[mid]<k)l=mid+1;
else r=mid;
}
if(a[r]!=k){
puts("-1 -1");
return;
}
while(a[--r]==k);
cout<<r<<" ";
while(a[++r]==k);
cout<<r-2<<endl;
}
int main( ){
std::ios::sync_with_stdio(false);
int m;
cin>>n>>m;
int l=1,r=n,k,i,j;
for(i=1;i<=n;i++)cin>>a[i];
for(i=1;i<=m;i++){
cin>>k;
find(k);
}
}
2.二分答案
也挺简单的,二分答案+差分维护在二分的答案下每天需要的教室数量
code:
#include<bits/stdc++.h>
using namespace std;
int n,cf[1000100],l[1000100],r[1000100],d[1000100],most[1000100];
inline bool check(int k){
memset(cf,0,sizeof(cf));
int i,j;
for(i=1;i<=k;i++){
cf[l[i]]+=d[i];
cf[r[i]+1]-=d[i];
}
for(i=1;i<=n;i++){
cf[i]+=cf[i-1];
if(cf[i]>most[i])return 0;
}
return 1;
}
int main( ){
int m,ll,rr,mid,i;
scanf("%d%d",&n,&m);
ll=1;rr=m;
for(i=1;i<=n;i++)scanf("%d",&most[i]);
for(i=1;i<=m;i++)scanf("%d%d%d",&d[i],&l[i],&r[i]);
if(check(m)){
puts("0");
return 0;
}
while(rr>ll){
mid=(ll+rr)/2;
if(check(mid))ll=mid+1;
else rr=mid;
}
puts("-1");
printf("%d",ll);
}
## 分割线
三分
由二分推广来的,主要解决单峰问题的
模板
code:求凸函数极限
double l=0,r=10000;
while(r-l>=0.01){//视精度而变化
double m1=l+(r-l)/3,m2=r-(r-l)/3;
if(f(m1)<f(m2))l=m1;
else r=m2;
}
return f(r);
为什么要将小的那一个赋值为新的区间端点呢?
这也是理解三分的重点
明显的,我们要首先满足区间内要包含顶点
我们取的端点里,可能会有1个端点(最多1个)越过了顶峰
但是值最小的一定不会越过
模板题
1.模板题
典型的三分,前面已经讲了
code:
#include<bits/stdc++.h>
using namespace std;
int n,a[10011],b[10011],c[10011];
inline double courage(double x,int i){return x*x*a[i]+x*b[i]+c[i];}
inline double check(double x){
double ans=courage(x,1);
int i,j,k;
for(i=2;i<=n;i++)
ans=max(ans,courage(x,i));
return ans;
}
inline void work( ){
cin>>n;
int i,j,k;
for(i=1;i<=n;i++)cin>>a[i]>>b[i]>>c[i];
double l=0,r=1000,emp=1e-11,mid1,mid2;
while(r-l>emp){
mid1=l+(r-l)/3.0;
mid2=r-(r-l)/3.0;
if(check(mid1)>check(mid2))l=mid1;
else r=mid2;
}
printf("%.4lf\n",check(l));
}
int main( ){
int t;
std::ios::sync_with_stdio(false);
cin>>t;
while(t--)work( );
}