알고리즘/비트마스크
[B1208] - 부분집합의 합2
tongnamuu
2018. 8. 29. 19:12
https://www.acmicpc.net/problem/1208
부분집합의 합 1에 이어 2입니다
이번엔 N이 40이 되었습니다.부분집합의 합 1처럼 모든 경우를 만든다면 틀리겠지만
20개씩 나누어서 각각 부분집합으로 만들 수 있는 수를 배열로 만든 후
sorting하여 합이 S가 되는 경우를 찾으면 됩니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 | #include <iostream> #include <vector> #include <algorithm> using namespace std; int main() { int n,s; cin >> n >> s; int m = n / 2; int l = n - m; long long ans = 0; vector<int>a(m); vector<int>up(1 << m); vector<int>b(l); vector<int>down(1 << l); for (int i = 0; i < m; i++) { cin >> a[i]; } for (int i = m,j=0; i < n; i++) { cin >> b[j++]; } for (int i = 0; i < (1 << m); i++) { for (int k = 0; k < m; k++) { if (i&(1 << k)) { up[i] += a[k]; } } } for (int i = 0; i < (1 << l); i++) { for (int k = 0; k < l; k++) { if (i&(1 << k)) { down[i] += b[k]; } } } sort(up.begin(), up.end()); sort(down.begin(),down.end()); int i = 0; int j = (1<<l)-1; while (i<(1 << m) &&j>=0) { if (up[i] + down[j] == s) { long long upcnt = 1; long long downcnt = 1; i++; j--; while (i<(1<<m)&&up[i] == up[i - 1]) { upcnt++; i++; } while (j>=0&&down[j] == down[j+ 1]) { downcnt++; j--; } ans += upcnt * downcnt; } else if (up[i] + down[j] < s) { i++; } else if (up[i] + down[j] > s) { j--; } } if (s == 0) ans--; cout << ans << '\n'; } | cs |