# Mất kết nối Tác giả : Vũ Phương (☞゚ヮ゚)☞ ## Tóm tắt đề : Bảo đẹp trai nghe tin có một khu đô thị gồm $n$ ngôi nhà, mỗi ngôi nhà thứ $i$ nằm ở tọa độ $a_i$, và trên đường thẳng đó có $m$ tháp điện mỗi tháp điện thứ $i$ nằm ở tọa độ $b_i$. ### Yêu cầu: * Tìm cường độ phát điện nhỏ nhất $x$ sao cho tất cả $n$ ngôi nhà đều nhận được điện từ ít nhất một tháp. * Một ngôi nhà $a_i$ sẽ nhận được điện từ tháp $b_j$ nếu $|a_i − b_j| \leq x$ ### Subtask - Subtask 1 : $n, m \leq 1000$ - Subtask 2 : $n, m \leq 10^4$ và $x \leq 10^3$ - Subtask 3 : Không có ràng buộc gì thêm. ## Subtask 1 : $n, m \leq 1000$ ### Thuật toán - Ta chỉ cần đơn giản duyệt qua từng ngôi nhà thứ $i$ tìm tháp điện $j$ sao cho $|a_i - b_j|$ nhỏ nhất. Kết quả chính là max giá trị để kết nối của mỗi ngôi nhà. ### Độ phức tạp: - Duyệt từng ngôi nhà và tháp điện $O(n * m)$. ### Code C++: ```cpp #include<bits/stdc++.h> #define endl '\n' #define int long long using namespace std; const int maxn = 1e6 + 5; int a[maxn], b[maxn], n, m; main() { ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); freopen("ketnoi.inp", "r", stdin); freopen("ketnoi.out", "w", stdout); int test = 1; cin >> test; while(test--) { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; int maxi = 0; for (int i = 1; i <= n; i++) { int mini = 1e18; for (int j = 1; j <= m; j++) { mini = min(mini, abs(a[i] - b[j])); } maxi = max(maxi, mini); } cout << maxi << endl; } } ``` --- ## Subtask 2 : $n, m \leq 10^4$ và $x \leq 10^3$ ### Thuật toán: - Vì giá trị cường độ điện $x$ được giới hạn, ta chỉ cần dùng 1 vòng for cố định giá trị $x$, và dùng thuật toán 2 con trỏ để kiểm tra xem cường độ $x$ có thỏa mãn hay không. ### Độ phức tạp: - Cố định giá trị $x$ và dùng 2 con trỏ để kiểm tra $O(10^3 * (n + m))$ --- ### Code C++: ```cpp const int maxn = 1e6 + 5; int a[maxn], b[maxn], n, m; bool check(int x) { int j = 1; for (int i = 1; i <= n; i++) { while(j <= m && b[j] < a[i] - x) { j++; } if (j <= m && abs(b[j] - a[i]) <= x) continue; return false; } return true; } main() { ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); freopen("ketnoi.inp", "r", stdin); freopen("ketnoi.out", "w", stdout); int test = 1; cin >> test; while(test--) { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; sort(a+1,a+n+1); sort(b+1,b+m+1); for (int x = 0; x <= 1000; x++) { if (check(x)) { cout << x << endl; break; } } } } ``` --- ## Subtask 3 : Không có ràng buộc gì thêm. ### Thuật toán: - Khi giải được subtask 2 thì subtask 3 cũng không quá khó để cải tiến, thay vì dùng 1 for để cố định giá trị $x$, ta chặt nhị phân giá trị $x$ và tiếp tục dùng 2 con trỏ để kiểm tra giá trị $x$ có thỏa mãn hay không. ### Độ phức tạp: - Chặt nhị phân đáp án và sử dụng 2 con trỏ để kiểm tra $O((n + m)*log(10^9))$ --- ### Code C++: ```cpp const int maxn = 1e6 + 5; int a[maxn], b[maxn], n, m; bool check(int x) { int j = 1; for (int i = 1; i <= n; i++) { while(j <= m && b[j] < a[i] - x) { j++; } if (j <= m && abs(b[j] - a[i]) <= x) continue; return false; } return true; } main() { ios_base::sync_with_stdio(0);cin.tie(0);cout.tie(0); freopen("ketnoi.inp", "r", stdin); freopen("ketnoi.out", "w", stdout); int test = 1; cin >> test; while(test--) { cin >> n >> m; for (int i = 1; i <= n; i++) cin >> a[i]; for (int i = 1; i <= m; i++) cin >> b[i]; sort(a+1,a+n+1); sort(b+1,b+m+1); int l = 0, r = 1e12, res = 0; while(l <= r) { int mid = (l + r)/2; if (check(mid)) { res = mid; r = mid - 1; } else l = mid + 1; } cout << res << endl; } } ```