report VI VI EN
Register | Login
  • HOME
  • PROBLEMSET
  • ROADMAP
  • COMPETITION
  • TOPIC
  • RANKING
  • GUIDE
  • MASHUP
  • ABOUT
  • CONTACT
Solutions of Subset sum 2 - FlandreOJ: Flandre Online Judge

Solutions of Subset sum 2

Select solution language

Write solution here.


User Avatar Defylogicguy    Created at    2 likes

### Tóm tắt bài toán Bài toán yêu cầu kiểm tra xem trong một mảng $A$ cho trước có tồn tại hay không một tập con các phần tử sao cho tổng của chúng bằng $k$. --- ### Hướng giải Áp dụng ý tưởng của kỹ thuật **Meet in the Middle**, ta chia mảng $A$ thành hai nửa. Từ đó, xây dựng hai mảng $M$ và $N$, trong đó mỗi mảng lưu tổng của **tất cả các tập con** tương ứng của mỗi nửa sau khi chia. Tiếp theo, ta duyệt qua từng phần tử $i$ trong $M$ (hoặc $N$) và kiểm tra xem trong mảng còn lại có tồn tại giá trị $k - i$ hay không. Việc kiểm tra này có thể được thực hiện hiệu quả bằng cách sử dụng **tìm kiếm nhị phân**, hoặc các cấu trúc dữ liệu như `set` hay `map` (trong code tham khảo mình dùng `set`). **Chú ý**: Do kiểu $A_i\leq10^{18}$ nên ta phải dùng `long long` thay vì `int` --- ### Độ phức tạp - Việc liệt kê tất cả các tổng tập con của mỗi nửa mảng có độ phức tạp $O\left(2^{\frac{N}{2}}\right)$. - Ta xét tất cả các phần tử trong một trong hai mảng $M$ hoặc $N$ sẽ mất $O\left(2^{\frac{N}{2}}\right)$ (Do $M$ và $N$ đều có khoảng $2^{\frac{N}{2}}$ phần tử). - Trong bước kiểm tra, sử dụng tìm kiếm nhị phân, `set` hoặc `map` đều có độ phức tạp $O\left(\frac{N}{2}\right)$. $\Rightarrow$ Tổng độ phức tạp của thuật toán là $O\left(\frac{N}{2} \times2^{\frac{N}{2}}\right)$, hoàn toàn phù hợp với giới hạn $N \leq 40$. --- ### Code tham khảo ```cpp #include <bits/stdc++.h> using namespace std; #define int long long int n, k; vector<int> a; void f(int idx, int end, vector<int> &b, int cur) { if (idx == end) { b.push_back(cur); return; } f(idx + 1, end, b, cur); cur += a[idx]; f(idx + 1, end, b, cur); } signed main() { cin >> n >> k; a.resize(n); for (int i = 0; i < n; i++) cin >> a[i]; vector<int> one, two; f(0, n / 2, one, 0); f(n / 2, n, two, 0); set<int> st(two.begin(), two.end()); for (int i : one) if (st.find(k - i) != st.end()) { cout << "YES\n"; return 0; } cout << "NO\n"; } ```