Problem
找到一個完備集合,其任兩個數字做 AND 和 OR 運算都在集合中。
給定部分集合,請問至少還需要幾個元素使得其變成完備集合。
1 2 3 4 5 6 7 8 9
| 4 5 0 1 3 5 7 2 2 4 3 3 7 11 3 1 2 4
|
Sample Output
1 2 3 4
| Case #1: 0 Case #2: 2 Case #3: 1 Case #4: 5
|
Solution
這一題從傳錯題目開始已經放著很久,當時怎麼樣都沒有想法,直接著手 O(n * 2^20)
最慘運行方式,其實這種複雜度與通過的複雜度就差那麼一點的 n。 // 肯定是死在 n。
其實可以發現到,假使挑選 i-th bit 很有可能會連帶其他的 bit 一同帶上,因此對於 i-th bit 最小化攜帶的 bit (做 AND 最小化)。
最後窮舉攜帶 i-th bit 是否要挑 (OR 所有攜帶的 bit),複雜度降至 O(2^20)
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
| #include <stdio.h> #include <math.h> #include <iostream> #include <algorithm> #include <vector> #include <queue> #include <map> #include <set> #include <string.h> #include <assert.h> using namespace std; int main() { int testcase, cases = 0; int n, x; scanf("%d", &testcase); while (testcase--) { scanf("%d", &n); set<int> S; int A[32] = {}, all = (1<<18) - 1; memset(A, -1, sizeof(A)); for (int i = 0; i < n; i++) { scanf("%d", &x); S.insert(x); all &= x; for (int j = 0; j < 18; j++) { if ((x>>j)&1) { if (A[j] == -1) A[j] = x; else A[j] = A[j] & x; } } } S.insert(all); int m = 0; for (int i = 0; i < 18; i++) { if (A[i] != -1) A[m++] = A[i]; } for (int i = 1; i < (1<<m); i++) { int num = 0; for (int j = 0; j < m; j++) { if ((i>>j)&1) { num |= A[j]; } } S.insert(num); } printf("Case #%d: %d\n", ++cases, (int)S.size() - n); } return 0; }
|