二分查找
这题可以二分查找,但是也可以直接用int ans=upper_bound(a,a+n,x)-a找出答案!!!
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N];
int main()
{
int n,x;
ios::sync_with_stdio(false);
while(cin>>n>>x)
{
for(int i=0;i<n;i++)
{
cin>>a[i];
}
int ans=upper_bound(a,a+n,x)-a;//c++自带,直接用于找第一个大于x的数的下标//
cout<<ans<<endl;
}
return 0;
}
自己写二分查找(这里借用nefu_liw的代码)
#include <bits/stdc++.h>
using namespace std;
int n,x,i,l,r,m,a[1000010];
int seek(int l,int r,int cmp)
{
while(l<=r)
{
m=l+(r-l)/2;
if(a[m]>cmp)r=m-1;
if(a[m]==cmp)return m+1;
if(a[m]<cmp)l=m+1;
}
return r+1;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>x)
{
for(i=0;i<n;i++)
cin>>a[i];
sort(a,a+n);
printf("%d\n",seek(0,n-1,x));
}
return 0;
}
小清新的二分查找之旅
常规的二分查找,模板题!!!
但是有一点要注意,二分的过程要写成函数,放在主函数外面,否则可能会TLE。。。。。。
#include<bits/stdc++.h>
using namespace std;
const int N=1e6+5;
int a[N];
int n,q,l,r,m,k;
bool panduan(int l,int r,int k)
{
while(l<=r)
{
m=(l+r)/2;
if(a[m]>k) r=m-1;
if(a[m]<k) l=m+1;
if(a[m]==k) return 1;
}
return 0;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>q)
{
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
while(q--)
{
cin>>k;
if(panduan(1,n,k)) printf("no\n");
else printf("YES\n");
}
}
return 0;
}
小清新的函数坐标-二分
#include<bits/stdc++.h>
using namespace std;
double f(double x)
{
return (0.0001*x*x*x*x*x+0.003*x*x*x+0.5*x-3);
}
double erfen(double l,double r,double y)
{
double m=l+(r-l)/2;
while(r-l>=1e-6)
{
if(f(m)<y) l=m;
if(f(m)>y) r=m;
if(f(m)==y) return m;//三种情况写清楚,否则会超时//
m=l+(r-l)/2;
}
return m;
}
int main()
{
double l,r,x,y;
while(scanf("%lf",&y)!=EOF)
{
l=-20.0,r=20.0;
x=erfen(l,r,y);
printf("%.4lf\n",x);
}
return 0;
}
小清新的二倍问题加强版-二分-桶排
不用二分,桶排打标记即可!!!
#include<bits/stdc++.h>
using namespace std;
int main()
{
ios::sync_with_stdio(false);
int n,t,max,count;
int a[100010];
while(cin>>n)
{
for(int j=0;j<n;j++)
{
memset(a,0,sizeof(a));
max=1,count=0;
while(cin>>t&&t!=0)
{
a[t]=1;
if(max<t)
max=t;
}
for(int i=1;i<=max/2;i++)//为了不OLE,这里i要小于等于最大值的一半,否则数组会越界,另一种解决办法是,定义数组是定义大一倍,也可以//
{
if(a[i]>0)
count+=a[2*i];
}
printf("%d\n",count);
}
break;
}
return 0;
}
简单几何-二分
#include<bits/stdc++.h>
using namespace std;
double PI=acos(-1);//π用acos(-1.0)表示//
double f(int h,double r)
{
return (PI*h*r*r-h*r-pow(r,PI));//v2-v1用原始式表示,化简的话。精度会出错//
}
double seek(double l,double r,int h)
{
double m=l+(r-l)/2.0;
while(l<r)
{
if(r-l<=1e-8) break;
if(f(h,m)<=0) r=m;//减小m(减小半径)
else l=m;//增大m(增大半径)
m=l+(r-l)/2.0;
}
return m;
}
int main()
{
int t,h;
ios::sync_with_stdio(false);
cin>>t;
while(t--)
{
cin>>h;
double l=0;
double r=100000;
double m=seek(l,r,h);
printf("%.4lf\n",m);
}
return 0;
}
小清新切绳子-二分
找符合条件的最大!!!
思路:
首先确定能剪出的绳子长度的范围,显然从0开始,至于最长,应该是n条绳子中最长的长度,因为有可能只让剪一条绳子,即范围是(0,maxlength],然后就是在这个范围之间进行二分,每次分出一个要剪的绳子长度,用这个长度去计算能剪出的绳子数,看是否符合条件即可!!! 需要注意的是,这个题要求的是符合条件的最长长度,因此要注意标记绳子长度那句话的位置,具体见代码:
#include<bits/stdc++.h>
using namespace std;
int n,k,ans,l,r,mid,li[10010];
bool check(int mid)
{
int count=0;
for(int i=0;i<n;i++)
{
count+=li[i]/mid;
}
return count>=k;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>k)
{
for(int i=0;i<n;i++)
{
cin>>li[i];
}
l=0,r=1e7;
while(l<=r)
{
mid=l+(r-l)/2;
if(check(mid))
ans=mid,l=mid+1;//找最大,ans=mid应放在这一句,如果找最小,应放在else里//
else
r=mid-1;
}
cout<<ans<<endl;
}
return 0;
}
卖古董-DP-二分
分成几段 {100,400}{300,100},{500},{101}{400};这里分成了5段; 每段都 <=500;
500是很多成功分段方案中,每段的最大值当中最小的一组;
思路::二分!分的是什么?是价格,首先还是找出要分的范围,显然最小是单个古董的最大价格,最大范围则应该是古董价格之和,然后进行二分,分出来的结果(拟最终结果)用来控制每天卖的价格,即每天买的价格不能超过这个价格,这里要找的是符合条件的最小值,所以要注意标记结果的位置,具体看代码::
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k;
int a[N];
int check(int x)
{
int count=0,flag=0,s=0;
for(int i=0;i<n;i++)
{
flag=0;
s+=a[i];
if(s>x)
{
s=a[i];
flag=1;
count++;
}
}
//if(flag==0)这里发现了一处错误,不需要判断是否flag等于0,都要count++,因为flag=0时自不必说,表示最后一轮得到的s<=x,但是当flag=1时,说明最后一轮的s是大于x的,因此count++了一次,但是现在s又是a【i】了,不过flag并没有变回0,因为恰好结束了循环,因此还是应该在循环外面再加一次的
count++;
if(count>k) return 1;
else return 0;
}
int main()
{
ios::sync_with_stdio(false);
int t;
cin>>t;
while(t--)
{
cin>>n>>k;
int maxn=0,sum=0,ans=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(maxn<a[i]) maxn=a[i];
sum+=a[i];
}
int l=maxn,r=sum,mid=0;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid)) l=mid+1;
else
{
ans=mid;//找最小值,放在else里//
r=mid-1;
}
}
cout<<ans<<endl;
}
return 0;
}
切绳子实数版-二分
因为实数很难处理,把实数变成整数来计算,主要是为了解决 23.456输出后会变成23.46的问题,而应该输出23.45! 另外当mid=0时要退出否则会RE!
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k,a[N];
double t;
bool check(int mid)
{
long long count=0;
for(int i=0;i<n;i++)
{
count+=(int)a[i]/mid;
}
return count>=k;
}
int main()
{
ios::sync_with_stdio(false);
while(cin>>n>>k)
{
int max=0;
for(int i=0;i<n;i++)
{
cin>>t;
a[i]=(int)(t*100);
if(max<a[i]) max=a[i];
}
int l=0,r=max,mid,ans=0;
while(l<=r)
{
mid=l+(r-l)/2.0;
if(mid==0) break;
if(check(mid))
{
ans=mid;
l=mid+1;
}
else
r=mid-1;
}
printf("%.2lf\n",ans/100.00);
}
return 0;
}
数列分段-二分
与卖古董是一个道理
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+5;
int n,k;
int a[N];
int check(int x)
{
int count=0,flag=0,s=0;
for(int i=0;i<n;i++)
{
flag=0;
s+=a[i];
if(s>x)
{
s=a[i];
flag=1;
count++;
}
}
if(flag==0)
count++;
if(count>k) return 1;
else return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>k;
int maxn=0,sum=0,ans=0;
for(int i=0;i<n;i++)
{
cin>>a[i];
if(maxn<a[i]) maxn=a[i];
sum+=a[i];
}
int l=maxn,r=sum,mid=0;
while(l<=r)
{
mid=(l+r)/2;
if(check(mid)) l=mid+1;
else
{
ans=mid;
r=mid-1;
}
}
cout<<ans<<endl;
return 0;
}
二分查找加强版
仅仅是再排一下序就OK了
#include<bits/stdc++.h>
using namespace std;
const int N=2e6+5;
int a[N];
int main()
{
int n,x;
ios::sync_with_stdio(false);
while(cin>>n>>x)
{
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
sort(a+1,a+1+n);
int ans=upper_bound(a+1,a+1+n,x)-(a+1);
cout<<ans<<endl;
}
return 0;
}