二分答案入門亂講

2022-05-02 03:48:07 字數 3137 閱讀 2043

//2023年12月有更新。

對於一些問題,它的解滿足單調性,即如果x滿足條件,則對於任意的 i ( 1<=i<=x) 或 (x <=i <=n) (假設1和n是答案的上下界)都會滿足條件。一般遇上這種問題,我們就可以用二分答案來加快解決。這種問題常常有關鍵語句:使最大......最小、……至少是多少、求出最少的……。

對於上面的問題,在沒學二分答案的時候,我們是這麼寫的:(假設答案是上界)

for(int i=1;i<=n;++i)

if(!check(i))

列舉答案,進行檢查。出現第乙個不合法的解,答案就是它前面那個值。但這樣看來,未免太慢。我們花了很長時間來檢查每乙個答案。如果答案是10000,我們就會做很多無用功。或者說我們列舉1000是正確的,那麼前999個都可以看成白列舉了,很浪費。

那麼我們該如何盡可能的少做這些無用功呢?

我們來設想一下。同樣假設答案是上界,如果我們check了10000,發現它是滿足解的,那麼答案肯定不小於10000。如果我們又check了 20000,發現它是滿足解的,那麼10000~20000內的數我們都不用列舉。又或者20000是不滿足解的,那麼答案就在10000~20000的 左閉右開區間內。這個時候我們如果」恰當地「check 15000,答案的範圍會進一步縮小。

看到這裡我們大概都會想到分塊或者二分了。一步一步地縮小答案範圍最終出解。

int l=1,r=n,ans=1;

while(l<=r)

printf("%d

",ans);

是啊,zz的板子誰都會。重點就在check函式上面。我們要使用時間複雜度優秀的check來寫。怎麼寫出最好的方法呢?分析題目,優化演算法,然後大膽猜想不用證明。多做題目,積累經驗(這是最吼的!)。然後因為我走歪了,check一向非主流,但莫名好用啊(有些題目的check只要有不合法就可以立即彈出,複雜度可以降到玄學級)一般二分答案複雜度是穩定的log(r-l+1),總複雜度是o(log*f(check))。

下面分享一些題目,都是noip裡面的水題,都是可以一遍ac的。

1.noip2015 河中跳房子

最大距離最小,一看就知道是二分答案。

那麼該如何寫check呢?

我們可以check當最大距離為mid時,所需要搬走的石頭的個數。方法就是乙個小小的貪心——能不拿走就不拿走,能少拿走就少拿走,然後一次check在o(n)的時間內跑過。總時間複雜度是o(nlogn)。

#include    #include    

#include

#include

int l,m,n,pla[50100

];int

gi()

int check(int

x) sta=pla[i];

}return

ans;

}using

namespace

std;

intmain()

printf("%d

",r);

}

我們check的返回值就是最少需要搬走的石頭個數,可以證明ans就是最優值。

2.noip2012 借教室

因為答案具有單調性——答案之前的肯定都能借到。所以我們來二分答案。

那麼該如何寫check函式呢?

對於這道題,我們需要幹的事有:區間增加和單點求值。可能大犇都想到了線段樹,但這種複雜度賊高的演算法最高只能過90分。我們沒必要用高階演算法,可以用一種小技巧處理——差分+字首和。

所 謂差分,就是把區間的操作轉移到對區間端點的操作。比如我們對乙個都是0的陣列,要在5~13這段區間加上3,只要在5這個點上加上3,在14這個點上減 掉3,這樣在算字首和的時候,0~4都是0,5~13都是3,14及以後又都成了0。這種操作修改是o(1),查詢是o(n),但你可以一遍查詢求出所有 的點是否合法。所以查詢的總複雜度就是o(n+m),題目的複雜度就是o((n+m)logm)。

#include    #include    

#include

using

namespace

std;

int n,m,num[1010000],d[1010000],sta[1010000],end[1010000],q[1010000

],l,r;

intgi()

bool check(int

x)

return

true;}

intmain()

if(l>m)printf("0"

);

else printf("

-1\n%d

",l);

return0;

}

我們check函式返回的是當前訂單能否滿足。

3.noip2011 聰明的質檢員

一看就知道是二分答案:答案具有單調性,影象趨勢類似於乙個二次函式曲線,我們只要求出這個函式的頂點最近的整數就好了。二分答案,記錄當前答案,比較一下就好了。

這裡要解釋一下那個式子的意思:l到r內所有滿足wj>w的j的個數乘以它們的體積和。這個可以用字首和維護。開兩個字首和維護一下個數和體積和就好了。

#include    #include    

#include

#include

#define ll long long intll n,m,s,l[

201000],r[201000],v[201000],w[201000],qnum[200100],qy[200100

],maxr;

ll gi()

ll max(ll x,ll y)

ll min(ll x,ll y)

ll check(ll x)

for(int i=1;i<=m;++i)

return ans-s;

}int

main()

printf(

"%lld\n

",k);

}return0;

}

check函式返回的是當前答案下的w的原值(不能帶abs())

如果小於0,證明這個點在原點右邊,要往左邊挪。否則往右邊挪。

那就這麼草率的結尾吧!

二分答案和三分入門

首先.我是乙個很菜很菜的萌新,所以這篇文章寫得很詳細,有很多我自己的口水話方便我理解,請各位謹慎食用qwq 以前在網上找過很多介紹二分的部落格,但都感覺對萌新不太友好,反正我當時連跳石頭都沒看懂,所以決定自己寫一篇!其中有我的想法,也借鑑了書裡的很多內容,感謝lyd。二分答案,顧名思義,就是對我們所...

二分查詢與二分答案

主要用於在乙個單調的函式中查詢某值 連續函式的情況 若當前查詢的區間是 l,r 查詢的值是 y 函式單增 設 mid l r 2 若 f mid y 則 l mid,否則 r mid 直至 r l eps 當前查詢的區間是 l,r 查詢的值是 y 函式單增 設 mid l r 2 若 f mid y...

二分查詢和二分答案

1.解釋 優點 查詢速度快。缺點 待查表為有序表。4.時間複雜度 o log n 5.示例 p2249查詢 include include using namespace std long long n,m,a 1000005 b 100005 l,r,mid,cnt,x intmain for i...