1. 程式人生 > 其它 >洛谷能力提升綜合題單 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一定

(書上似乎有錯誤,理解不能,先略過)

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

名師大將莫自牢,千軍萬馬避白袍