大一寒假集训(6)---二分法

本文深入解析二分法的基本原理及应用技巧,通过多个实战案例,如查找、切绳子问题、函数坐标求解等,展示二分法在算法竞赛和实际编程中的高效运用。

大一寒假集训(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啦

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值