Hướng dẫn giải của [2526 KSCUM TT2] Câu 3: COTCHAN


Chỉ dùng lời giải này khi không có ý tưởng, và đừng copy-paste code từ lời giải này. Hãy tôn trọng người ra đề và người viết lời giải.
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

Hãy đọc nội quy trước khi bình luận.


Không có bình luận tại thời điểm này.