大一寒假集训(6)—二分法 nefu
(1) 10个数最多只需查找7次,100个数最多查找14次,位数每多1 ,查找次数加7(最多)。
(2)二分法模板
while (r-l>0)
{
mid=(r+l)/2;
if (ans>y)//y为要找的目标值
r=mid;
else l=mid;
}
(3)c++中含有二分法的函数
upper_bound 返回第一个大于的元素的下标
lower_bound 返回第一个大于等于元素的下标
1.小清新的二倍问题加强版-二分-桶排 nefu 1647
注意本题为单组输入 我因为写成多组输入而被OLE卡了很长时间
我因此发现了一般OLE都是因为把单组输入当成多组输入而写!!!!ヽ(#`Д´)ノ┌┛〃

#include <bits/stdc++.h>
using namespace std;
int a[10005];
int b[300005];
int main()
{
ios::sync_with_stdio(false);
int n,r;
while (cin>>n)
{
while (n--)
{
int i;
int ans=0;
int x,p;
memset(b,0,sizeof(b));
p=0;
while (cin>>x&&x!=0)
{
a[++p]=x;
b[a[p]]++;
}
//sort(a+1,a+1+p);
for (i=1;i<=p;i++)
if (b[a[i]]==1&&b[a[i]*2]==1)
ans++;
cout<<ans<<endl;
}
}
return 0;
}
2.二分查找 nefu 956
c++中有二分查找的函数,直接套用即可(⁎˃ᴗ˂⁎)
#include <bits/stdc++.h>
using namespace std;
int a[1000008];
int main()
{
int n,x;
while (scanf("%d %d",&n,&x)!=EOF)
{
int m;
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
m=upper_bound(a,a+n,x)-a;
printf("%d\n",m);
}
return 0;
}
3.二分查找加强版 nefu 1245
(((((ી(・◡・)ʃ)))))
和上一道题比,只多一个排序
#include <bits/stdc++.h>
using namespace std;
int a[2000010];
int main()
{
int n,x;
while (scanf("%d %d",&n,&x)!=EOF)
{
int m;
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
sort(a,a+n);
m=upper_bound(a,a+n,x)-a;
printf("%d\n",m);
}
return 0;
}
4.小清新的二分查找之旅 nefu 1646
(◕ᴗ◕✿)
#include <bits/stdc++.h>
using namespace std;
int a[1000010];
int main()
{
int n,q;
ios::sync_with_stdio(false);
while (cin>>n>>q)
{
for (int i=1;i<=n;i++)
cin>>a[i];
int x,m;
for (int r=0;r<q;r++)
{
cin>>x;
m=lower_bound(a+1,a+n+1,x)-a;//注意lower_bound与upper_bound的区别
if (a[m]==x)
printf("no\n");
else printf("YES\n");
}
}
return 0;
}
5.小清新的函数坐标-二分 nefu 1645
(≖ᴗ≖)✧
#include <bits/stdc++.h>
using namespace std;
int main()
{
double y;
double x;
ios::sync_with_stdio(false);
while (cin>>y)
{
double r=20.0;
double l=-20.0;
double mid;
double ans;
while (r-l>0.0000001)
{
mid=(r+l)/2;
ans=mid*mid*mid*mid*mid*0.0001+mid*mid*mid*0.003+mid*0.5-3;
if (ans>y)
r=mid;
else l=mid;
}
printf("%.4lf\n",mid);
}
return 0;
}
6.简单几何-二分 nefu 1303
(。◕ˇ∀ˇ◕)
#include <iostream>
#include <bits/stdc++.h>
using namespace std;
const double p=acos(-1.0);//定义Π ?
int main()
{
int t;
scanf("%d",&t);
while (t--)
{
int h;
double m,ans;
scanf("%d",&h);
double l,r,mid;
double v1,v2;
l=0;
r=1e5;
while (r-l>=1e-8)//这里不能写r>l,因为是double,不可能循环到两者相等
{
mid=(l+r)/2.0;
v1=mid*h;
v2=p*mid*mid*h;
if (v2-v1<=pow(mid,p))
{
ans=mid;
r=mid;
}
else l=mid;
}
printf("%.4lf\n",ans);
}
return 0;
}
以下的四道题都是一个套路
7.小清新切绳子-二分 nefu 1648
(*๓´╰╯`๓)(・ω<) てへぺろ
#include <bits/stdc++.h>
using namespace std;
int n,k;
int a[1000000];
int check(int d)
{
int ans=0;
int i;
for (i=0;i<n;i++)
ans+=a[i]/d;
if (ans>=k) return 1;//
else return 0;
}
int main()
{
while (scanf("%d %d",&n,&k)!=EOF)
{
for (int i=0;i<n;i++)
scanf("%d",&a[i]);
int l,r,mid,x;
int maxn;
maxn=a[0];
for (int i=0;i<n;i++)
if (maxn<a[i])
maxn=a[i];
l=0;r=maxn;
while (r>=l)
{
mid=(r+l)/2;
if(check(mid)==1)
{
x=mid;l=mid+1;
}
else r=mid-1;
}
printf("%d\n",x);
}
return 0;
}
8.切绳子实数版-二分 nefu 1751
本题只需将上一题输入的数乘100,按整数算,再将输出除以100即可( • ̀ω•́ )✧^_-)≡★
#include <bits/stdc++.h>
using namespace std;
int n,k;
double a[1000000];
int check(int d)
{
int ans=0;
int i;
for (i=0;i<n;i++)
ans+=a[i]/d;
if (ans>=k) return 1;
else return 0;
}
int main()
{
while (scanf("%d %d",&n,&k)!=EOF)
{
for (int i=0;i<n;i++)
{
scanf("%lf",&a[i]);
a[i]=a[i]*100;//转化为整数
}
int l,r,mid;
double x;
int maxn;
maxn=a[0];
for (int i=0;i<n;i++)
if (maxn<a[i])
maxn=a[i];
l=0;r=maxn;
while (r>=l)
{
mid=(r+l)/2;
if(check(mid)==1)
{
x=mid;l=mid+1;
}
else r=mid-1;
}
printf("%.2lf\n",x/100);
}
return 0;
}
9.卖古董-DP-二分 nefu 1211

我太难了|*´Å`)ノ
#include <bits/stdc++.h>
using namespace std;
int a[100005];//注意数组大小
int r,l;
int mid;
int n,m;
int check(int d)
{
int q=0;
int day=1;//注意day初始值为1而不是0,因为day++时已经完成一组分段了
for (int j=1; j<=n; j++)
{
if (q+a[j]<=d)
q+=a[j];//注意此处应为<=
else
{
day++;
q=a[j];
}
}
if (day<=m) return 1;
else return 0;
}
int main()
{
int t;
ios::sync_with_stdio(false);
cin>>t;
while (t--)
{
cin>>n>>m;//m天
for (int i=1; i<=n; i++)
cin>>a[i];
int sum=0;
int ans;//答案
int maxn=a[1];
for (int i=1; i<=n; i++)
{
sum+=a[i];
if (maxn<a[i])
maxn=a[i];
}
r=sum;
l=maxn;
while (r>=l)//不要忘了等号,不然会WA WA WA
{
mid=(r+l)/2;
if (check(mid)==1)
{
ans=mid;
r=mid-1;
}
else
l=mid+1;
}
cout<<ans<<endl;
}
return 0;
}
10.数列分段-二分 nefu 1733
和8题相似,这里不过多解释(๑╹◡╹)ノ"""
#include <bits/stdc++.h>
using namespace std;
int r,l,mid;
int n,m;
int a[100005];
int sum,ans;
int check(int x)
{
int y=0;
int s=1;
for (int i=1;i<=n;i++)
{
y+=a[i];
if (y>mid)
{
y=a[i];
s++;
}
}
if (s>m) return 1;
else return 0;
}
int main()
{
ios::sync_with_stdio(false);
cin>>n>>m;//n为个数,m为分段数
for (int i=1;i<=n;i++)
{
cin>>a[i];
sum+=a[i];
}
int maxn=a[1];
for (int i=1;i<=n;i++)
{
if (a[i]>maxn)
maxn=a[i];
}
l=maxn;r=sum;
while(r>=l)
{
mid=(r+l)/2.0;
if (check(mid)==1)
l=mid+1;
else {
r=mid-1;
ans=mid;
}
}
cout<<ans<<endl;
return 0;
}
( ̄▽ ̄)~*AK啦
本文深入解析二分法的基本原理及应用技巧,通过多个实战案例,如查找、切绳子问题、函数坐标求解等,展示二分法在算法竞赛和实际编程中的高效运用。
1206

被折叠的 条评论
为什么被折叠?



