洛谷能力提升综合题单 Part 2.3 二分答案(仍为编辑完成)

洛谷能力提升综合题单 Part 2.3 二分答案(仍为编辑完成)

 

#include<bits/stdc++.h>
using namespace std;
int j;
double a,b,c,d,m;
double fc(double x)
{
    return a*x*x*x+b*x*x+c*x+d;
}
int main()
{
    cin>>a>>b>>c>>d;
    for(double i=-100;i<=100;i++)
    {
        double l=i;
        double r=i+1;
        if(!fc(l))
        {
            printf("%.2lf ",l);
        }
        if(fc(l)*fc(r)<0)
        {
            while(r-l>=0.001)
            {
                m=(l+r)/2;
                if(fc(l)*fc(m)<=0)
                {
                    r=m;
                }
                else if(fc(l)*fc(m)>0)
                {
                    l=m;
                }
            }
            printf("%.2lf ",r);
            j++;
        }
        if(j==3)
        {
            break;
        }
    }
    return 0;
}

第一题思路非常明显

在区间内,每次加1,根据性质若出现<0的,则对长度为1的区间进行二分。

 

二分的基础用法是在单调序列或单调函数中进行查找。

使用条件:单调性

复杂度:判定小于求解

 

整数域上:

1.终止边界

2.左右区间取舍时的开闭情况

 

实数域:

1.精度

 

整数集合上的二分

最终答案处于[l,r]以内,循环以l==r结束,每次二分中间值mid会归属于左半段或右半段二者之一

 

在单调递增序列a中查找大于等于x的数中最小的一个

while(l<r)
    {
        int mid=(l+r)/2;
        if(a[mid]>=x)
        {
            r=mid;
        }
        else
        {
            l=mid+1;
        }
    }    
    return a[l];

 

在单调递增序列a中查找小于等于x的数中最大的一个

while(l<r)
    {
        int mid=(l+r+1)/2;
        if(a[mid]<=x)
        {
            l=mid;
        }
        else
        {
            r=mid-1;
        }
    }
    return a[l];

注意到mid有两种写法1

1.

int mid=(l+r)/2;
        if(a[mid]>=x)
        {
            r=mid;
        }
        else
        {
            l=mid+1;
        }

2.

int mid=(l+r+1)/2;
        if(a[mid]<=x)
        {
            l=mid;
        }
        else
        {
            r=mid-1;
        }

认真观察可知,二分核心是减小观察区间。

对于第二段,若mid取l+r,极限情况r只比l大1的情况下,

若a[mid]<=x,mid==l,则区间并未缩小,进入死循环。

若走else,r<l,循环不能以r==l结束

 

分析还可知,mid=(l+r)/2取不到r,mid=(l+r+1)/2取不到l。

 

处理无解的情况,把最初的二分区间[1,n]扩大到[1,n+1]或[0,n],把a数组一个越界的下标包含进来。

若二分终止于越界下标上,则说明a中不存在所求的数。

 

实数域上的二分

确定需要的精度eps,l+eps<r为循环条件,一般需要保留k位小数的时候,取eps=10^-(k+2)

while(l+1e-5<r)
    {
        double mid=(l+r)/2;
        if(calc(mid))
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }

 

若需要更高精度,可以固定循环次数的二分方法

for(int i=0;i<100;i++)
    {
        double mid=(l+r)/2;
        if(calc(mid))
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }

 

拓展:

三分求单峰函数极值

单峰函数:

拥有唯一的极大值点,极大值左侧严格单调上升,右侧严格单调下降

单谷函数:

或相反拥有唯一的极小值点。。。。。。

1.若f(lmid)<f(rmid),分析可知,可能两点在极大值左边/两点在极大值左右,XXX一定

(书上似乎有错误,理解不能,先略过)

 

 

洛谷能力提升综合题单 Part 2.3 二分答案(仍为编辑完成)

 

 

#include<bits/stdc++.h>
using namespace std;
int a[50001];
int l,n,m,mid,ans;
int half(int x)
{
    int s=0,num=0;
    for(int i=1;i<=n;i++)
    {
        if(a[i]-s<x)
        {
            num++;
        }
        else
        {
            s=a[i];
        }
    }
    if(num>m)
    {
        return 0;
    }
    return 1;
}
int main()
{
    /*while(l+1e-5<r)
    {
        double mid=(l+r)/2;
        if(calc(mid))
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }*/
    /*for(int i=0;i<100;i++)
    {
        double mid=(l+r)/2;
        if(calc(mid))
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }*/
    //int l,n,m;
    cin>>l>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    int ll=0,rr=l;
    a[n+1]=l;
    while(ll<rr)
    {
        mid=(ll+rr+1)/2;
        if(half(mid))
        {
            ll=mid;
            ans=mid;
        }
        else
        {
            rr=mid-1;
        }
    }
    cout<<ans;
    return 0;
}

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

上一篇:mysql排它锁之行锁,服务之间的调用为啥不直接用HTTP而用RPC


下一篇:第三周作业:卷积神经网络(Part 1)