Hướng giải của Đếm tập con tổng X
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.
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 A thành hai nửa trái và phải. Với mỗi nửa, sinh toàn bộ tổng các tập con (tối đa 2^{N/2} tập). Sắp xếp mảng tổng của nửa phải. Duyệt từng tổng s của nửa trái, dùng chặt nhị phân (bisect) trên nửa phải để đếm số lần xuất hiện của X - s.
Độ phức tạp: O(2^{N/2} × log(2^{N/2})) = 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 ans = 0;
for (long long s : sumL) {
long long need = X - s;
auto lo = lower_bound(sumR.begin(), sumR.end(), need);
auto hi = upper_bound(sumR.begin(), sumR.end(), need);
ans += hi - lo;
}
cout << ans << '\n';
return 0;
}Python
python
from bisect import bisect_left, bisect_right
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()
ans = 0
for s in sumL:
need = x - s
ans += bisect_right(sumR, need) - bisect_left(sumR, need)
return ans
n, x = map(int, input().split())
a = list(map(int, input().split()))
print(solve(n, x, a))
Nhận xét