2020.1.5 大一寒假集训六 二分查找

关于lower_bound( )和upper_bound( )的常见用法

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;
}

你可能感兴趣的:(2020.1.5 大一寒假集训六 二分查找)