Hướng giải của Tập con gần X nhất


Nhớ rằng hướng dẫn giải này chỉ nên sử dụng khi bế tắc, và tuyệt đối không nên sao chép mã nguồn kèm theo. Hãy tôn trọng tác giả bài tập và người viết hướng dẫn giải.
Nộp mã nguồn lời giải chính thức trước khi giải bài tập đó có thể khiến bạn bị ban.

Ý tưởng

Chia mảng thành hai nửa, sinh toàn bộ tổng tập con của mỗi nửa. Sắp xếp mảng tổng nửa phải. Với mỗi tổng s của nửa trái, chặt nhị phân tìm vị trí idx sao cho sumR[idx] gần nhất với X - s. So sánh 2 vị trí lân cận (idx-1 và idx) để cập nhật kết quả.

Độ phức tạp: O(2^{N/2} × N) thời gian, O(2^{N/2}) bộ nhớ.

C++ cpp #include <bits/stdc++.h> using namespace std; int main() { ios::sync_with_stdio(false); cin.tie(nullptr); int n; long long X; cin >> n >> X; vector<long long> a(n); for (auto &x : a) cin >> x; int n1 = n / 2, n2 = n - n1; vector<long long> left(a.begin(), a.begin() + n1); vector<long long> right(a.begin() + n1, a.end()); vector<long long> sumL, sumR; for (int mask = 0; mask < (1 << n1); ++mask) { long long s = 0; for (int i = 0; i < n1; ++i) if (mask >> i & 1) s += left[i]; sumL.push_back(s); } for (int mask = 0; mask < (1 << n2); ++mask) { long long s = 0; for (int i = 0; i < n2; ++i) if (mask >> i & 1) s += right[i]; sumR.push_back(s); } sort(sumR.begin(), sumR.end()); long long best_sum = LLONG_MIN; long long best_diff = LLONG_MAX; for (long long s : sumL) { long long need = X - s; auto it = lower_bound(sumR.begin(), sumR.end(), need); if (it != sumR.end()) { long long total = s + *it; long long diff = abs(total - X); if (diff < best_diff || (diff == best_diff && total > best_sum)) { best_diff = diff; best_sum = total; } } if (it != sumR.begin()) { --it; long long total = s + *it; long long diff = abs(total - X); if (diff < best_diff || (diff == best_diff && total > best_sum)) { best_diff = diff; best_sum = total; } } } cout << best_sum << '\n'; return 0; }
Python python from bisect import bisect_left def solve(n, x, a): n1, n2 = n // 2, n - n // 2 left, right = a[:n1], a[n1:] sumL = [] for mask in range(1 << n1): s = 0 for i in range(n1): if mask >> i & 1: s += left[i] sumL.append(s) sumR = [] for mask in range(1 << n2): s = 0 for i in range(n2): if mask >> i & 1: s += right[i] sumR.append(s) sumR.sort() best_sum = -10**30 best_diff = 10**30 for s in sumL: need = x - s idx = bisect_left(sumR, need) for cand_idx in (idx - 1, idx): if 0 <= cand_idx < len(sumR): total = s + sumR[cand_idx] diff = abs(total - x) if diff < best_diff or (diff == best_diff and total > best_sum): best_diff = diff best_sum = total return best_sum n, x = map(int, input().split()) a = list(map(int, input().split())) print(solve(n, x, a))

Nhận xét

Không có ý kiến tại thời điểm này.