Binary_Search_Problem_APPLICATION === [Link](URL) ----- ### Hướng dẫn Vào thời điểm $x$, người thứ $k$ làm được $\left \lfloor \frac{x}{T_k} \right \rfloor$ hồ sơ. Nên ta có tổng cộng $f(x) = \overset{n}{\underset{k = 1}{\Large \Sigma}} \left \lfloor \frac{x}{T_k} \right \rfloor$ hồ sơ được làm Nhiệm vụ của ta là tìm số $x$ nhỏ nhất thỏa $f(x) \geq m$ Nhận thấy vì $T_k > 0\ \forall\ k = 1 \dots n$ nên ta có $f(x) \leq f(x + 1)\ \forall\ x \geq 0$. Hay dãy $f(x)$ tăng đơn điệu. - Nếu $f(p) \geq m$ thì $f(q) \geq m\ \forall\ q \geq p$ - Nếu $f(p) < m$ thì $f(q) < m\ \forall\ q < p$ Vậy ta dùng chặt nhị phân, bắt đầu với một đoạn $[L, R]$ mỗi bước chọn một vị trí $x$ ở giữa đoạn. - Nếu $f(x) \geq m$ thì kết quả hoặc là $x$ hoặc là nhỏ hơn $x$ nhưng chắc chắn không thể lớn hơn $x$. Nên gán $R := x - 1$ và cập nhật kết quả $x$ hiện tại là tốt nhất - Nếu $f(x) < m$ thì kết quả không thể nhỏ hơn hoặc bằng $x$. Nên gán $L := x + 1$ Trong trường hợp xấu nhất $T_k = 10^9$ với mọi $k$ làm cho hàm $f(x)$ tăng chậm và $m = 10^{18}$ để $x$ cần tìm phải lớn nhất thì kết quả là $10^{18}$. Ngược lại trong trường hợp tốt nhất khi $m = 0$ có kết quả nhỏ nhất cần tìm là $0$ Nên ta phải thử đoạn $[L, R] = [0, 10^{18}]$ ----- ### Độ phức tạp Xét đoạn $[L, R]$ bất kì, nếu ta chọn một vị trí $x$ thì ta xét đoạn $[L, x)$ hoặc $(x, R]$ trong bước tiếp theo. Trong trường hợp xấu nhất ta phải chọn đoạn có độ dài lớn hơn Để tối ưu, ta sẽ chọn vị trí $x$ sao cho nó nằm ở giữa $[L, R]$. Khi này mỗi bước độ dài giảm đi khoảng $1$ nửa. Nên sẽ lặp số lần là $max(k | 2^k \leq R - L + 1) = O(log_2(r - l + 1))$ ----- ### Code > **Time:** $O(n + log_2(10^{18}))$ > **Space:** $O(n)$ > **Algo:** Binary Search, Implementation, Basic Math ```cpp= #include <iostream> #include <cstdio> using namespace std; void file(const string FILE = "Test") { freopen((FILE + ".INP").c_str(), "r", stdin); freopen((FILE + ".OUT").c_str(), "w", stdout); } typedef long long ll; const ll LINF = 0x3f3f3f3f3f3f3f3f; const int INF = 0x3f3f3f3f; const int LIM = 1e5 + 15; int n, m; int T[LIM]; bool check(ll x) { ll cnt = 0; for (int i = 1; i <= n; ++i) { cnt += x / T[i]; if (cnt >= m) return true; /// Da lam du ho so } return false; /// Chua lam du ho so } int main() { ios::sync_with_stdio(NULL); cin.tie(NULL); file("APPLICATION"); cin >> n >> m; for (int i = 1; i <= n; ++i) cin >> T[i]; ll res = -1; for (ll l = 0, r = +LINF; l <= r; ) { ll x = (l + r) >> 1; if (check(x)) /// Doan [x, +oo) deu thoa { res = x; r = x - 1; } else /// Doan [0, x] deu khong thoa { l = x + 1; } } cout << res; return 0; } ```