Hướng dẫn giải của Câu 3 (Tuyển sinh chuyên Tin Bình Dương 2023-2024)


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

Cho N khối hình vuông có độ cách nhiệt ai. Cần xếp chúng thành một dãy sao cho tổng a1 + ... + aN + tổng max(0, a{i+1} - ai) là lớn nhất. Tổng ai không đổi khi đổi thứ tự, nên chỉ cần tối đa hóa phần cộng thêm tổng max(0, a{i+1} - ai).

Sub 1: Vét cạn — ~O(n! \cdot n)~, dùng khi ~n \le 8~

Thử mọi cách xếp (hoán vị) của N khối, tính phần cộng thêm của từng cách rồi lấy cách lớn nhất. Dùng next_permutation trên dãy đã sắp xếp để duyệt đủ mọi hoán vị.

Chấm riêng sub này: đúng 6/50 test (các test có N <= 8 đều đúng).

Sub 2: Công thức — ~O(n \log n)~, dùng cho mọi n

Sắp xếp dãy b tăng dần. Ta chia các khối thành nhóm, mỗi nhóm xếp liền nhau theo thứ tự tăng dần thì phần cộng thêm của nhóm là (max - min). Tối ưu khi ghép từng cặp (bi nhỏ, b{N-1-i} lớn) cho i = 0..N/2-1, khối ở giữa (nếu N lẻ) đứng riêng và không cộng thêm gì. Đáp án là tổng ai + tổng (b{N-1-i} - b_i).

Ví dụ: N = 4, a = 5 4 1 7. Sắp xếp được 1 4 5 7, ghép (1, 7) và (4, 5): cộng thêm 6 + 1 = 7. Tổng là 17 + 7 = 24.

Bẫy: tổng có thể lên tới 10^5 · 10^4 = 10^9 nên dùng long long để an toàn.

Chương trình hoàn chỉnh

main đọc N và các a_i, nếu N <= 8 gọi sub1, còn lại gọi sub2.

#include <bits/stdc++.h>
using namespace std;

int n;
long long a[100005];  // độ cách nhiệt của các khối hình vuông

// Tổng a không phụ thuộc cách xếp, nên chỉ cần tối đa hóa phần cộng thêm: tổng max(0, a[i+1]-a[i]).

// Sub 1: vét cạn — thử mọi cách xếp (hoán vị) và lấy cách có tổng cộng thêm lớn nhất. Dùng khi n <= 8.
void sub1() {
    vector<long long> v(a + 1, a + n + 1);
    sort(v.begin(), v.end());
    long long sum = 0, best = 0;
    for (long long x : v) sum += x;
    do {
        long long extra = 0;
        for (int i = 0; i + 1 < n; i++)
            extra += max(0LL, v[i + 1] - v[i]);
        best = max(best, extra);
    } while (next_permutation(v.begin(), v.end()));
    cout << sum + best << "\n";
}

// Sub 2: công thức. Chia dãy thành các nhóm, mỗi nhóm xếp tăng dần thì được cộng (max - min) của nhóm.
// Tốt nhất là ghép b[i] (nhỏ) với b[n-1-i] (lớn) cho i = 0..n/2-1, phần còn lại (nếu có) đứng riêng. O(n log n).
void sub2() {
    vector<long long> b(a + 1, a + n + 1);
    sort(b.begin(), b.end());
    long long ans = 0;
    for (long long x : b) ans += x;
    for (int i = 0; i < n / 2; i++)
        ans += b[n - 1 - i] - b[i];
    cout << ans << "\n";
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    cin >> n;
    for (int i = 1; i <= n; i++) cin >> a[i];
    if (n <= 8) sub1();  // dữ liệu nhỏ: thử mọi cách xếp
    else sub2();         // công thức
    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.