fork download
  1. // equal_subset_sum.cpp
  2. // Tìm hai subset khác nhau có cùng tổng cho n <= 42
  3. // - Sử dụng meet-in-the-middle để kiểm tra các subset nằm hoàn toàn trong 1 nửa
  4. // - Nếu chưa tìm được, dùng sampling (ngẫu nhiên / hoặc liệt kê khi n nhỏ) trên toàn bộ không gian tập con
  5. // Đầu vào: n (<=42) rồi n số nguyên a[i]
  6. // Đầu ra: in ra tổng S và hai tập con (danh sách chỉ số 0-based) có cùng tổng; nếu không tìm thấy in thông báo.
  7.  
  8. #include <bits/stdc++.h>
  9. using namespace std;
  10. using ll = long long;
  11. using ull = unsigned long long;
  12.  
  13. void print_solution(ll S, ull mask1, ull mask2, int n) {
  14. cout << "Found S = " << S << '\n';
  15. // in chỉ số 0-based
  16. vector<int> v1, v2;
  17. for (int i = 0; i < n; ++i) {
  18. if ((mask1 >> i) & 1ULL) v1.push_back(i);
  19. if ((mask2 >> i) & 1ULL) v2.push_back(i);
  20. }
  21. cout << "Subset 1 (indices, 0-based): ";
  22. for (size_t i = 0; i < v1.size(); ++i) {
  23. if (i) cout << ' ';
  24. cout << v1[i];
  25. }
  26. cout << '\n';
  27. cout << "Subset 2 (indices, 0-based): ";
  28. for (size_t i = 0; i < v2.size(); ++i) {
  29. if (i) cout << ' ';
  30. cout << v2[i];
  31. }
  32. cout << '\n';
  33. // optional: print values
  34. if (!v1.empty()) {
  35. cout << "Subset 1 values: ";
  36. for (size_t i = 0; i < v1.size(); ++i) {
  37. if (i) cout << ' ';
  38. // note: caller must have a in scope to print values; we'll skip here
  39. cout << "a[" << v1[i] << "]";
  40. }
  41. cout << '\n';
  42. }
  43. }
  44.  
  45. int main() {
  46. ios::sync_with_stdio(false);
  47. cin.tie(nullptr);
  48.  
  49. int n;
  50. if (!(cin >> n)) return 0;
  51. vector<ll> a(n);
  52. for (int i = 0; i < n; ++i) cin >> a[i];
  53.  
  54. if (n == 0) {
  55. cout << "No elements\n";
  56. return 0;
  57. }
  58.  
  59. int left = n / 2;
  60. int right = n - left;
  61. int L = 1 << left; // <= 2^21 typically
  62. int R = 1 << right;
  63.  
  64. // 1) enumerate left subsets, detect duplicates inside left
  65. unordered_map<ll, ull> map_left; // sum -> mask (mask uses full n-bit representation: lower left bits used)
  66. map_left.reserve(L * 2);
  67. vector<ll> sums_left(L, 0);
  68. map_left[0] = 0ULL; // empty
  69. for (int mask = 1; mask < L; ++mask) {
  70. int lsb = mask & -mask;
  71. int prev = mask ^ lsb;
  72. int idx = __builtin_ctz((unsigned)lsb); // index inside left
  73. sums_left[mask] = sums_left[prev] + a[idx];
  74. ll s = sums_left[mask];
  75. ull fullmask = (ull)mask; // occupies bits [0..left-1]
  76. auto it = map_left.find(s);
  77. if (it != map_left.end()) {
  78. ull other = it->second;
  79. if (other != fullmask) {
  80. print_solution(s, other, fullmask, n);
  81. return 0;
  82. }
  83. } else {
  84. map_left[s] = fullmask;
  85. }
  86. }
  87.  
  88. // 2) enumerate right subsets, detect duplicates inside right and cross with left
  89. unordered_map<ll, ull> map_right; // sum -> mask (full representation shifted)
  90. map_right.reserve(R * 2);
  91. vector<ll> sums_right(R, 0);
  92. map_right[0] = 0ULL; // empty (no bits set in right part)
  93. for (int mask = 1; mask < R; ++mask) {
  94. int lsb = mask & -mask;
  95. int prev = mask ^ lsb;
  96. int idx = __builtin_ctz((unsigned)lsb); // index inside right
  97. sums_right[mask] = sums_right[prev] + a[left + idx];
  98. ll s = sums_right[mask];
  99. ull fullmask = ((ull)mask) << left; // shift to high bits
  100. // duplicate inside right
  101. auto itR = map_right.find(s);
  102. if (itR != map_right.end()) {
  103. ull other = itR->second;
  104. if (other != fullmask) {
  105. print_solution(s, other, fullmask, n);
  106. return 0;
  107. }
  108. } else {
  109. map_right[s] = fullmask;
  110. }
  111. // cross left vs right: left subset sum == right subset sum
  112. auto itL = map_left.find(s);
  113. if (itL != map_left.end()) {
  114. ull leftmask = itL->second;
  115. // ensure different subsets overall
  116. if (leftmask != fullmask) {
  117. print_solution(s, leftmask, fullmask, n);
  118. return 0;
  119. }
  120. }
  121. }
  122.  
  123. // 3) Nếu vẫn chưa có (ít khả năng theo giả thiết), thử sampling trên toàn bộ không gian subset
  124. // Dùng bảng hash sum -> mask, sample nhiều mask (toàn bộ nếu n <= 22), hoặc random nếu n > 22.
  125.  
  126. unordered_map<ll, ull> full_map;
  127. const ull MAX_SAMPLE = (1ULL << 21); // khoảng ~2 triệu
  128. ull limit_samples = 0;
  129. if (n <= 22) {
  130. limit_samples = 1ULL << n; // enumerate toàn bộ (2^n) nếu nhỏ
  131. } else {
  132. limit_samples = MAX_SAMPLE; // sample this many random subsets
  133. }
  134. full_map.reserve((size_t)min(limit_samples, (ull)2000000ULL) * 2);
  135.  
  136. // if enumerating all subsets (n small)
  137. if (n <= 22) {
  138. ull total = 1ULL << n;
  139. vector<ll> dp(total, 0);
  140. for (ull mask = 1; mask < total; ++mask) {
  141. ull lsb = mask & -mask;
  142. ull prev = mask ^ lsb;
  143. int idx = __builtin_ctzll(lsb);
  144. dp[mask] = dp[prev] + a[idx];
  145. ll s = dp[mask];
  146. auto it = full_map.find(s);
  147. if (it != full_map.end()) {
  148. ull other = it->second;
  149. if (other != mask) {
  150. print_solution(s, other, mask, n);
  151. return 0;
  152. }
  153. } else {
  154. full_map[s] = mask;
  155. }
  156. }
  157. } else {
  158. // random sampling
  159. mt19937_64 rng(chrono::high_resolution_clock::now().time_since_epoch().count());
  160. unordered_set<ull> seen_masks;
  161. seen_masks.reserve((size_t)min(limit_samples, (ull)2000000ULL));
  162. for (ull iter = 0; iter < limit_samples; ++iter) {
  163. ull mask = rng();
  164. if (n < 64) mask &= ((1ULL << n) - 1ULL);
  165. // avoid duplicate masks in sampling
  166. if (seen_masks.find(mask) != seen_masks.end()) continue;
  167. seen_masks.insert(mask);
  168. // compute sum
  169. ull tmp = mask;
  170. ll s = 0;
  171. while (tmp) {
  172. int b = __builtin_ctzll(tmp);
  173. s += a[b];
  174. tmp &= tmp - 1ULL;
  175. }
  176. auto it = full_map.find(s);
  177. if (it != full_map.end()) {
  178. ull other = it->second;
  179. if (other != mask) {
  180. print_solution(s, other, mask, n);
  181. return 0;
  182. }
  183. } else {
  184. full_map[s] = mask;
  185. }
  186. }
  187. }
  188.  
  189. cout << "Không tìm được hai subset khác nhau cùng tổng (bất ngờ; có thể do giới hạn sampling)." << '\n';
  190. return 0;
  191. }
  192.  
Success #stdin #stdout 0.01s 5324KB
stdin
4
1 2 4 7
stdout
Found S = 7
Subset 1 (indices, 0-based): 0 1 2
Subset 2 (indices, 0-based): 3
Subset 1 values: a[0] a[1] a[2]