---
# System prepended metadata

title: 二分搜與對答案二分搜

---

# 二分搜與對答案二分搜

對答案二分搜是個針對模擬問題的一種優化方式，在結果的上下界容易求出，並且結果具有單調性，就能利用二分搜來進行優化。
## 二分搜
>給定一升序排序過的整數陣列，大小為n，給定一整數d，求陣列中第一個$\geq n$的數字的index。

首先第一個最直接的想法，就是直接將整個陣列掃描一遍，直到找到第一個$\geq n$的數字即可。然而這樣的演算法效率較差，複雜度為$O(n)$。

再次觀察題目，會發現我們沒有充分利用陣列是升序排序過的性質。如果在一個位置的數字小dn，那在其左邊的位置皆不可能是答案，同樣地，如果一個數字大於等於d，那答案一定不會在它的右邊。利用這個性質，我們可以每次都從要搜尋的區間檢查其最中間的數字，然後用結果來更新搜尋區間的左右界。由於每次搜尋區間都會被切一半，複雜度為$O(logn)$，大幅度地優化了演算法。

面對二分搜的問題，首先要做的就是先找出「單調性」，也就是在某種比較大小的定義下滿足遞增或遞減(未必是數字上的大小，例如std::pair的比較)，再去利用上下界來二分搜。

有關單調性的更詳細說明，請參考[wiwiho大佬的筆記](https://hackmd.io/@wiwiho/CPN-monotone-and-order)





以下是有關二分搜的題目：
[CF 706B](https://codeforces.com/problemset/problem/706/B/)
[TIOJ 1044](https://tioj.ck.tp.edu.tw/problems/1044)
[TOI2021入營考pC](https://hackmd.io/@SorahISA/toi2021)(LIS的$O(nlogn)$實作 )

## 對答案二分搜

>APCS2017P3
>給定在+x軸整數點的n個位置，求最小的區間大小使得K個區間能覆蓋所有n個整數點

由於點的位置跟分散程度都未知，似乎沒有一個快速的解法，只能利用模擬來求解。首先，答案不需要求出區間的位置，因此我們只需要找到最小的區間大小即可。

最直覺的想法是將區間大小由1慢慢增加並驗證，並且因為區間的放置可以貪婪地將左界放在第一個未覆蓋的點上，驗證可以在O(n)做完。然而，逐一遞增區間大小效率非常差，如果最左與最右的點位置相差d，時間複雜度為$O(dn)$，因此我們需要優化它。

觀察題目，會發現如果答案為X，那區間大小$\geq X$的情況一定能覆蓋，區間大小$< X$的一定不能完全覆蓋，發現了單調性的存在，似乎可以做二分搜，上下界分別為$\lceil \frac{d}{K} \rceil$和1，那麼我們就可以對區間大小做二分搜，達到$O(nlogd)$的好複雜度。

總結來說，對答案二分搜是利用答案與某個變數的單調性(例如大於等於答案就可做，小於則不行)，來減少模擬的情況。

以下是對答案二分搜的一些題目：
[APCS200704P3](https://zerojudge.tw/ShowProblem?problemid=f581)
[TOI2021入營考pB](https://hackmd.io/@SorahISA/toi2021)

## 參考資料
https://hackmd.io/@gilbert33/r1MIpp0Fv?print-pdf#/
https://hackmd.io/@wiwiho/CPN-monotone-and-order
https://hackmd.io/@SorahISA/toi2021