標籤:設定 檢查 判斷 集合 相對 是的 範圍 要求 math
太極生兩儀,兩儀生四象,四象生八卦,陰陽交媾萬物生。
若要你在全校同學當中猜我心裡想的那個人,允許你問若干個問題,使問問題次數盡量少,你肯定會問我那個人是男生還是女生。因為這樣,可以篩掉一半的人。並且在數學期望上來說,你肯定會盡量問一些能篩掉一半的問題,將問題的答案集合一分為二。假設你直接問是不是***,我說不是的話,你這個問題就問得十分無力了,因為它只幫你排除了一個人。所以,每次問可以篩掉一半備選集合的問題,顯然是一種很聰明的做法。
世間萬物始於混沌,根據太極生兩儀,兩儀生四象,四象生八卦,我們可以很快將萬事萬物分為八類,並且都相對均衡,這種古老的大智慧,在很久很久以前就被古人所運用了。
在\(OI\)界,這就叫二分。一分為二,天地初開。
對於一個包含了最終解的集合,若我們能通過一次判斷將其一分為二,將最終解的範圍縮小一半,那麼這就是二分。就比如,假如整數範圍\([l,r]\)是解集範圍,並且這個解具有單調性(不存在\(i\)是解但是\(j\)不是解且\(j>i\)),那麼只要\(mid=(l+r)/2\)是解,\([mid+1,r]\)就都是解集,我們再去\([l,mid-1]\)裡找更加小的解。因為滿足單調性,二分多用於解決“最大值最小”或者“最小值最大”的問題。我要求某個問題的答案最大值最小的那一個,說明只要大於等於這個答案的都是問題的解,不過不是最小的。最小值最大同理。
至於二分的寫法,網上千千萬,我個人偏愛一下這一種:
int l=mn,r=mx,ans;while(l<=r) { int mid=(l+r)>>1; if(check(mid))ans=mid,l=mid+1; else r=mid-1;}//最小值最大
int l=mn,r=mx,ans;while(l<=r) { int mid=(l+r)>>1; if(check(mid))ans=mid,r=mid-1; else l=mid+1;}//最大值最小
因為\(mid\)已經被檢查過並且用於更新\(ans\)了,所以剩下倆區間就是\([l,mid-1]\)和\([mid+1,r]\)了,選擇哪個繼續去更新答案根據實際情況定就行。
然後實數二分的話只要設定一個\(eps\)判一判就行了:
double l=mn,r=mx,ans;while(l+eps<=r) { double mid=(l+r)/2; if(check(mid))ans=mid,r=mid-eps; else l=mid+eps;}
以上就是二分的板子了。至於怎麼去二分和怎麼去\(check\),那就得根據實際題目實際設定了。
淺談二分