PROBLEM
lower_bound( )和upper_bound( )都是利用二分查找的方法在一个排好序的数组中进行查找的。
lower_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于或等于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
upper_bound( begin,end,num):从数组的begin位置到end-1位置二分查找第一个大于num的数字,找到返回该数字的地址,不存在则返回end。通过返回的地址减去起始地址begin,得到找到数字在数组中的下标。
二分查找
#include
#include
using namespace std;
int a[1000005];
int main()
{
int i,ans;
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
ans=upper_bound(a,a+n,m)-a;
printf("%d\n",ans);
}
return 0;
}
二分查找加强版
#include
#include
using namespace std;
int a[2000005];
int main()
{
int i,ans;
int n,m;
while(~scanf("%d%d",&n,&m))
{
for(i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
ans=upper_bound(a,a+n,m)-a;
printf("%d\n",ans);
}
return 0;
}
小清新的二分查找之旅
#include
#include
using namespace std;
int a[1000001];
int main()
{
int m,n;
int ans;
int i,j;
int k;
while(~scanf("%d%d",&n,&m))
{
for( i=0;i<n;i++)
scanf("%d",&a[i]);
for( j=0;j<m;j++)
{
scanf("%d",&k);
ans=lower_bound(a,a+n,k)-a;
if(a[ans]==k)
printf("no\n");
else printf("YES\n");
}
}
return 0;
}
小清新的函数坐标-二分
#include
using namespace std;
double f(double x)
{
double res;
res=0.0001*pow(x,5.0) + 0.003*pow(x,3.0)+ 0.5*x - 3.0;
return res;
}
int main()
{
double y,x,mid,l,r;
while(scanf("%lf",&y)!=-1)
{
l=-20.0;
r=20.0;
while(l<r)
{
if (r-l<1e-8) break;
mid=(l+r)/2.0;
if (f(mid)>y)
r=mid;
else
l=mid;
}
printf("%.4lf\n",mid);
}
return 0;
}
简单几何-二分
#include
using namespace std;
const double pi=acos(-1.0);
int h;
int check(double r)
{
if (pow(r,pi)>=h*(pi*r*r-r))
return 1;
else
return 0;
}
int main()
{
int t;
double l,r,mid;
scanf("%d",&t);
while(t--)
{
scanf("%d",&h);
l=0;r=100000;
while(l<r)
{
mid=(l+r)/2.0;
if (r-l<=1e-8) break;
if (check(mid)==1)
r=mid;
else
l=mid;
}
printf("%.4lf\n",mid);
}
return 0;
}
小清新切绳子-二分
二分check()函数总结:一些值都符合条件,也就是求最大值时,check()函数 >=k时为返回1,对应的答案也在check() 返回1时记录就行!
当一些值都符合条件,也就是求最小值时,check()函数>k返回为1,对应的答案在=号的位置,也就是check()返回0时记录就行!
#include
using namespace std;
const int N=1e4+5;
int a[N];
int n,k;
int check(int d)
{
int num=0,s=0;
for(int i=1;i<=n;i++)
num+=a[i]/d;
if (num>=k) return 1;
else return 0;}
int main()
{
ios::sync_with_stdio(0);
while(cin>>n>>k)
{
int mx=-999999999;
for(int i=1;i<=n;i++)
{cin>>a[i];
if (mx<a[i]) mx=a[i];
}
int l=0,r=mx,mid=0;
int ans=0;
while(l<=r)
{
mid=(l+r)/2;
//if (r-l<=1e-8) break;
if (check(mid)==1)
ans=mid,l=mid+1;
else
r=mid-1;
}
cout<<ans<<endl;
}
return 0;}
切绳子实数版-二分
因为实数很难处理,把实数变成整数来计算,主要是为了解决 23.456输出后会变成23.46的问题,而应该输出23.45!
另外当mid=0时要退出否则会RE!
#include
using namespace std;
const int N=1e5+5;
int n,k;
int a[N];
double t;
int check(int x)
{
long long num=0;
for(int i=1;i<=n;i++)
num+=(int)(a[i]/x);
if (num>=k) return 1;
else
return 0;
}
int main()
{
ios::sync_with_stdio(0);
int mx=-99999999;
cin>>n>>k;
for(int i=1;i<=n;i++)
{
cin>>t;
a[i]=(int)(t*100);
if (mx<a[i]) mx=a[i];
}
int l=0,r=mx,mid=0,ans=0;
while(l<=r)
{
mid=(l+r)/2.0;
if (mid==0) break;
if (check(mid)==1)
ans=mid,l=mid+1;
else
r=mid-1;
}
printf("%.2lf\n",ans/100.00);
return 0;
}
卖古董-DP-二分
#include
using namespace std;
int main()
{
int t,n,m,num[100000],l,r,mid,max,ans,min,sum,cnt;
scanf("%d",&t);
while(t--)
{
scanf("%d %d",&n,&m);
sum=ans=max=0;
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
if(num[i]>max)max=num[i];
sum+=num[i];
}
min=l=max;
r=sum;
while(l<=r)
{
cnt=0;
sum=0;
mid=(l+r)/2;
for(int i=0;i<n;i++)
{
if(sum+num[i]<=mid)sum+=num[i];
else
{
sum=num[i];
cnt++;
}
}
if(cnt>=m)l=mid+1;
else r=mid-1;
}
printf("%d\n",l);
}
return 0;
}
数列分段-二分
与上一题类似;
左边界是所有数中最大的那个数
右边界是所有数的和
#include
using namespace std;
int main()
{
int n,m,num[100000],l,r,mid,max,ans,sum,cnt;
while(scanf("%d %d",&n,&m)!=-1)
{
sum=ans=max=0;
for(int i=0;i<n;i++)
{
scanf("%d",&num[i]);
if(num[i]>max)max=num[i];
sum+=num[i];
}
l=max;
r=sum;
while(l<=r)
{
cnt=0;
sum=0;
mid=(l+r)/2;
for(int i=0;i<n;i++)
{
if(sum+num[i]<=mid)sum+=num[i];
else
{
sum=num[i];
cnt++;
}
}
if(cnt>=m)l=mid+1;
else r=mid-1;
}
printf("%d\n",l);
}
return 0;
}