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