Hướng dẫn giải của [2526 KSCUM TT2] Câu 3: COTCHAN
Nộp một lời giải chính thức trước khi tự giải là một hành động có thể bị ban.
Hướng dẫn giải
Yêu cầu: sau khi thêm tối đa ~k~ cột chắn tại vị trí nguyên, tìm khoảng trống lớn nhất nhỏ nhất có thể đạt được. Đó chính là giá trị ~Q~ lớn nhất thoả đề.
Sub 1: Thử mọi cách chia với n = 3 — ~O(k)~, dùng khi ~n = 3,\ k \le 1000~
Có hai khoảng trống. Thử mọi cách dành ~j~ cột cho khoảng thứ nhất và ~k - j~ cột cho khoảng thứ hai. Một khoảng ~g~ chia được ~j+1~ đoạn thì đoạn dài nhất là ~\lceil g/(j+1) \rceil~.
Nếu chỉ nộp sub này: đúng 6/20 test (các test thuộc miền ~n = 3~).
Sub 2: Tìm nhị phân trên Q — ~O(n \log C)~
Với một giá trị ~Q~, mỗi khoảng ~g~ cần ~\lceil g/Q \rceil - 1~ cột để mọi đoạn không vượt quá ~Q~. Nếu tổng số cột này không lớn hơn ~k~ thì ~Q~ khả thi. Hàm này đơn điệu nên tìm nhị phân được ~Q~ nhỏ nhất khả thi.
Nếu chỉ nộp sub này: đúng 20/20 test.
Chương trình hoàn chỉnh
Chương trình đọc dữ liệu, sắp xếp các cột. Nếu ~n = 3~ và ~k \le 1000~ thì gọi sub 1, còn lại gọi sub 2. Sub sau có sai hoặc chưa kịp làm thì vẫn ăn điểm sub trước.
#include <bits/stdc++.h>
using namespace std;
int n;
long long K; // số cột chắn được thêm tối đa
vector<long long> x; // toạ độ các cột đã sắp xếp tăng dần
// Sub 1: n = 3, thử mọi cách chia K cột vào hai khoảng O(K)
// Khoảng g chia thành (j+1) đoạn thì đoạn dài nhất là ceil(g/(j+1)).
void sub1() {
long long g1 = x[1] - x[0], g2 = x[2] - x[1];
long long best = LLONG_MAX;
for (long long j = 0; j <= K; j++) {
long long a = (g1 + j) / (j + 1); // ceil(g1 / (j+1))
long long b = (g2 + (K - j)) / (K - j + 1); // ceil(g2 / (K-j+1))
best = min(best, max(a, b));
}
cout << best << "\n";
}
// Sub 2: tìm nhị phân trên Q — lời giải đầy đủ
// Muốn mọi đoạn <= Q thì khoảng g cần ceil(g/Q) - 1 cột thêm vào.
bool ok(long long Q) {
long long need = 0;
for (int i = 1; i < n; i++) {
long long g = x[i] - x[i - 1];
need += (g + Q - 1) / Q - 1;
if (need > K) return false;
}
return need <= K;
}
void sub2() {
long long lo = 1, hi = 0;
for (int i = 1; i < n; i++) hi = max(hi, x[i] - x[i - 1]);
while (lo < hi) {
long long mid = lo + (hi - lo) / 2;
if (ok(mid)) hi = mid;
else lo = mid + 1;
}
cout << lo << "\n";
}
int main() {
freopen("COTCHAN.INP", "r", stdin);
freopen("COTCHAN.OUT", "w", stdout);
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin >> n >> K;
x.resize(n);
for (auto &v : x) cin >> v;
sort(x.begin(), x.end());
if (n == 3 && K <= 1000) sub1();
else sub2();
return 0;
}
Bình luận