优美的暴力
参考博客:1 2 3
基本操作 参考:link
Functions
Examples
(constructor)
bitset<16> foo;
bitset<20> bar(233);
bitset<8> baz(std::string("01001"));
applicable operators
^
&
| <<
>>
~
==
!=
^=
&=
|= <<=
>>=
operator[]
Access bit
foo[1]
count
Count bits set
foo.count()
size
Return size
foo.size()
test
Return bit value
foo.test(i)
any
Test if any bit is set
foo.any()
none
Test if no bit is set
foo.none()
all
Test if all bits are set
foo.all()
set
Set bits
foo.set()
foo.set(2,0)
foo.set(2)
reset
Reset bits
foo.reset()
foo.reset(1)
flip
Flip bits
foo.flip()
foo.flip(2)
to_string
Convert to string
foo.to_string()
to_ulong
Convert to unsigned long interger
foo.to_ulong()
to_ullong
Convert to unsigned long long
foo.to_ullong()
练习 poj2443 Set Operation 题目链接
bitset
存储每个点属于哪些集合,询问时 &
起来不为零输出 Yes
,否则输出 No
.
复杂度:$O\left(\frac{QN}{32}\right)$
>folded 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 #include <algorithm> #include <vector> #include <cstdio> #include <bitset> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;int n, q;bitset<1005> bs[10005 ]; int main () { read (n); for (int i = 1 ; i <= n; i++){ int c, a; read (c); while (c--){ read (a); bs[a].set (i); } } read (q); while (q--){ int x, y; read (x, y); if ((bs[x] & bs[y]) != 0 ) puts ("Yes" ); else puts ("No" ); } return 0 ; }
hdu5036 Explosion 题目链接
整体的期望次数等于打开每扇门的期望被炸次数之和。考虑门 $i$,设所有能到达 $i$ 的点构成集合 $S_i$(包括 $i$ 本身),则在任一合法炸门序列中,若已经有一个不同于 $i$ 且可到达 $i$ 的点出现了,那么 $i$ 的被炸次数为 $0$;否则,没有任何钥匙可以打开它,$i$ 必须被炸一次。于是打开第 $i$ 扇门的期望被炸次数为 $0\cdot\frac{|S_i|-1}{|S_i|}+1\cdot\frac{1}{|S_i|}=\frac{1}{|S_i|}$,答案为 $\sum\limits_{i=1}^n\frac{1}{|S_i|}$.
为求出 $|S_i|$,我们可以利用 floyd
算法求出连通性,并利用 bitset
加速。
复杂度:$O\left(\frac{n^3}{32}\right)$
>folded 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 #include <cstdio> #include <bitset> using namespace std;const int N = 1005 ;int T, n;bitset<N> bs[N]; inline void floyd () { for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= n; j++) if (bs[j].test (i)) bs[j] |= bs[i]; } int main () { scanf ("%d" , &T); for (int CASES = 1 ; CASES <= T; CASES++){ scanf ("%d" , &n); for (int i = 1 ; i <= n; i++){ bs[i].reset (); bs[i].set (i); } for (int i = 1 ; i <= n; i++){ int c, x; scanf ("%d" , &c); while (c--){ scanf ("%d" , &x); bs[x].set (i); } } floyd (); double ans = 0 ; for (int i = 1 ; i <= n; i++) ans += 1.0 / bs[i].count (); printf ("Case #%d: %.5f\n" , CASES, ans); } return 0 ; }
Gym100342 J - Triatrip 题目链接
每个点用 bitset
记录出边连接哪些点以及入边连接哪些点,统计答案的时候与起来数 $1$ 的个数。
复杂度:$O(\frac{n^3}{32})$
>folded 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 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <bitset> using namespace std;typedef long long LL;const int N = 1505 ;int n;LL ans; char s[N];bitset<N> in[N], out[N]; int main () { freopen ("triatrip.in" , "r" , stdin); freopen ("triatrip.out" , "w" , stdout); scanf ("%d" , &n); for (int i = 1 ; i <= n; i++){ scanf ("%s" , s+1 ); for (int j = 1 ; j <= n; j++) if (s[j] == '+' ){ in[j].set (i); out[i].set (j); } } for (int i = 1 ; i <= n; i++) for (int j = 1 ; j <= n; j++) if (in[i].test (j)) ans += (out[i] & in[j]).count (); printf ("%lld\n" , ans / 3 ); return 0 ; }
hdu5313 Bipartite Graph 题目链接
先 $dfs$ 染色得到一系列二分图,然后重点在 $dp$.
设 $dp[i][k]$ 表示能否通过合并前 $i$ 个二分图构成一边是 $k$ 个点的二分图。则 $dp[i][k]=dp[i-1][k-a[i]]\ \mathrm{OR}\ dp[i-1][k-b[i]]$. 这个 $dp$ 是 $O(n^2)$ 的,由于 $dp$ 数组是 $bool$ 值,所以可以用 bitset
优化——把第一维滚掉,第二维就是 bitset
的每一位。
>folded 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 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <bitset> #include <vector> using namespace std;typedef long long LL;typedef pair<int , int > pii;#define mp(x, y) make_pair(x, y) #define pb(x) emplace_back(x) const int N = 10005 ;int T, n, m;struct Edge { int nxt, to; }edge[N*N]; int head[N], edgeNum;void addEdge (int from, int to) { edge[++edgeNum] = (Edge){head[from], to}; head[from] = edgeNum; } bool vis[N];int cnt[2 ];vector<pii> v; void dfs (int x, int c) { vis[x] = true ; cnt[c]++; for (int i = head[x]; i; i = edge[i].nxt){ if (vis[edge[i].to]) continue ; dfs (edge[i].to, c ^ 1 ); } } bitset<N> dp; inline void init () { memset (head, 0 , sizeof head); memset (vis, 0 , sizeof vis); edgeNum = 0 ; v.clear (); dp.reset (); } int main () { scanf ("%d" , &T); while (T--){ scanf ("%d%d" , &n, &m); init (); for (int i = 1 ; i <= m; i++){ int u, v; scanf ("%d%d" , &u, &v); addEdge (u, v); addEdge (v, u); } for (int i = 1 ; i <= n; i++){ if (!vis[i]){ cnt[0 ] = cnt[1 ] = 0 ; dfs (i, 0 ); v.pb (mp (cnt[0 ], cnt[1 ])); } } dp.set (0 ); for (int i = 0 ; i < v.size (); i++) dp = (dp << v[i].first) | (dp << v[i].second); int ans = 0 ; for (int i = 0 ; i < n; i++) if (dp.test (i)) ans = max (ans, i * (n - i) - m); printf ("%d\n" , ans); } return 0 ; }
hdu5890 Eighty seven 题目链接
设 $dp[i][j][k]$ 表示前 $i$ 个数选取 $j$ 个数能否凑出 $k$,则不考虑去掉 $3$ 个数的话,$dp[i][j][k]=dp[i-1][j-1][k-a[i]]\ \mathrm{OR}\ dp[i-1][j][k]$. 和上一题同理,滚动数组滚掉第一维,bitset
优化第三维。每次操作都重新求一遍 $dp$ 数组,时间有点吃紧,可以记忆化一下(虽然理论上最差复杂度没变)。
>folded 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 #include <algorithm> #include <iostream> #include <cstring> #include <cstdio> #include <bitset> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;int T, n, a[55 ], q;bitset<88> dp[15 ]; int ok[55 ][55 ][55 ];int main () { read (T); while (T--){ read (n); memset (ok, -1 , sizeof ok); for (int i = 1 ; i <= n; i++) read (a[i]); read (q); while (q--){ int x, y, z; read (x, y, z); if (ok[x][y][z] != -1 ){ puts (ok[x][y][z] ? "Yes" : "No" ); continue ; } dp[0 ].set (0 ); for (int j = 1 ; j <= 10 ; j++) dp[j].reset (); for (int i = 1 ; i <= n; i++) if (i != x && i != y && i != z) for (int j = 10 ; j >= 1 ; j--) dp[j] |= (dp[j-1 ] << a[i]); ok[x][y][z] = ok[x][z][y] = dp[10 ].test (87 ); ok[y][x][z] = ok[y][z][x] = dp[10 ].test (87 ); ok[z][x][y] = ok[z][y][x] = dp[10 ].test (87 ); puts (dp[10 ].test (87 ) ? "Yes" : "No" ); } } return 0 ; }
hdu5808 Price List Strike Back 题目链接
正解是 CDQ 分治,不过可以用 bitset
加速 $dp$ 过这道题。
先将所有商店和询问按距离排序,这样我们可以用一个指针不断后移指出哪些店距离小于询问距离。开一棵树状数组记录每种价格的个数,然后做一个多重背包的可行性 $dp$,用 bitset
优化。
不过时间还是有点吃紧,还可以优化:1. 做背包的时候一旦发现可行就退出;2. 在总价格为 $s$ 时,价格为 $k$ 的点最多只用 $\frac{s}{k}$ 个;3. 多重背包用二进制优化。
>folded 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 87 88 89 90 91 92 93 94 95 96 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;const int N = 20005 ;const int M = 100005 ;int T, n, m;bitset<101> dp; bool ans[M];struct Shop { int v, d, id; bool operator < (const Shop &A) const { return d < A.d; } }shop[N]; struct Query { int l, r, d, s, id; bool operator < (const Query &A) const { return d < A.d; } }q[M]; bool cmp (const Query &A, const Query &B) { return A.id < B.id; } struct Node { int val[105 ]; }c[N]; inline int lowbit (int x) { return x & -x; }inline void add (int x, int v) { while (x <= n){ c[x].val[v]++; x += lowbit (x); } } inline void sum (int x, int a[]) { for (int i = 1 ; i <= 100 ; i++) a[i] = 0 ; while (x){ for (int k = 1 ; k <= 100 ; k++) a[k] += c[x].val[k]; x -= lowbit (x); } } int L[105 ], R[105 ];inline bool solve (int i) { sum (q[i].r, R), sum (q[i].l-1 , L); if (R[q[i].s] - L[q[i].s]) return true ; dp.reset (), dp.set (0 ); for (int k = 1 ; k <= q[i].s; k++){ int cnt = min (R[k] - L[k], q[i].s / k); for (int j = 1 ; j <= cnt; cnt -= j, j <<= 1 ){ dp |= (dp << (k * j)); if (dp.test (q[i].s)) return true ; } if (cnt > 0 ) dp |= (dp << (k * cnt)); if (dp.test (q[i].s)) return true ; } return dp.test (q[i].s); } int main () { read (T); while (T--){ read (n, m); memset (c, 0 , sizeof c); for (int i = 1 ; i <= n; i++) read (shop[i].v), shop[i].id = i; for (int i = 1 ; i <= n; i++) read (shop[i].d); sort (shop+1 , shop+n+1 ); for (int i = 1 ; i <= m; i++) read (q[i].l, q[i].r, q[i].d, q[i].s), q[i].id = i; sort (q+1 , q+m+1 ); int pts = 0 ; for (int i = 1 ; i <= m; i++){ while (pts < n && shop[pts+1 ].d <= q[i].d){ pts++; add (shop[pts].id, shop[pts].v); } ans[q[i].id] = !solve (i); } for (int i = 1 ; i <= m; i++) printf ("%d" , ans[i]); puts ("" ); } return 0 ; }
CF981E Addition on Segments 题目链接
把所有操作放到线段树上,$dfs$ 这颗线段树,当到达叶节点时,我们得到了包含这个叶节点的一系列操作。如果只进行这些操作而不进行不包含该节点的操作的话,这个节点的值就一定是最大值,所以此时做一个 $01$ 背包的可行性 $dp$,用 bitset
优化。为降低复杂度,一路搜索下来时边走边 $dp$,同时记录上一层的 $dp$ 值便于回溯时撤销。
复杂度:$O(\frac{qn\lg n}{32})$
>folded 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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;const int N = 10005 ;int n, q;bitset<N> ans; struct segTree { int l, r; vector<int > v; }tr[N<<2 ]; #define lid id<<1 #define rid id<<1|1 #define mid ((tr[id].l + tr[id].r) >> 1) void build (int id, int l, int r) { tr[id].l = l, tr[id].r = r; tr[id].v.clear (); if (tr[id].l == tr[id].r) return ; build (lid, l, mid); build (rid, mid+1 , r); } void add (int id, int l, int r, int val) { if (tr[id].l == l && tr[id].r == r){ tr[id].v.emplace_back (val); return ; } if (r <= mid) add (lid, l, r, val); else if (l > mid) add (rid, l, r, val); else add (lid, l, mid, val), add (rid, mid+1 , r, val); } bitset<N> dp; void dfs (int id) { bitset<N> rec = dp; for (auto k: tr[id].v) dp |= dp << k; if (tr[id].l == tr[id].r){ for (int i = 1 ; i <= n; i++) if (dp.test (i)) ans.set (i); dp = rec; return ; } dfs (lid), dfs (rid); dp = rec; } int main () { scanf ("%d%d" , &n, &q); build (1 , 1 , n); while (q--){ int l, r, x; scanf ("%d%d%d" , &l, &r, &x); add (1 , l, r, x); } dp.reset (), dp.set (0 ); dfs (1 ); printf ("%d\n" , (int )ans.count ()); for (int i = 1 ; i <= n; i++) if (ans.test (i)) printf ("%d " , i); puts ("" ); return 0 ; }
poj1742 Coins 题目链接
多重背包的可行性问题,bitset
+ 二进制优化。
>folded 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 #include <algorithm> #include <cstring> #include <cstdio> #include <bitset> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;const int N = 105 ;const int M = 100005 ;int n, m, a[N], c[N];bitset<M> dp; bitset<M> mask; int main () { while (1 ){ read (n, m); if (!n && !m) break ; for (int i = 1 ; i <= n; i++) read (a[i]); for (int i = 1 ; i <= n; i++) read (c[i]); dp.reset (), dp.set (0 ); for (int i = 1 ; i <= n; i++){ for (int p = 1 ; p <= c[i]; c[i] -= p, p <<= 1 ) dp |= dp << (p * a[i]); dp |= dp << (c[i] * a[i]); } mask.reset (); for (int i = 0 ; i <= m; i++) mask.set (i); dp &= mask; printf ("%d\n" , (int )dp.count () - 1 ); } return 0 ; }
CSU2005 Nearest Maintenance Point 题目链接
如果不要求输出最近点,那么以所有的特殊点为源跑一遍 $dijkstra$ 即可。现在为了记录哪些点是最近点,采用 bitset
,在松弛操作时更新即可。
>folded 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 87 88 89 90 #include <bits/stdc++.h> using namespace std;typedef long long LL;const int N = 10005 ;const int M = 50005 ;const int INF = 1e9 ;int n, m, s, q, func[N];vector<int > spec; struct Edge { int nxt, to, dis; }edge[M<<1 ]; int head[N], edgeNum;void addEdge (int from, int to, int dis) { edge[++edgeNum].nxt = head[from]; edge[edgeNum].to = to; edge[edgeNum].dis = dis; head[from] = edgeNum; } struct Node { int dis, num; bool operator < (const Node &a) const { return a.dis < dis; } }; int dis[N];bool inS[N];bitset<1005> bs[N]; void dijkstra () { priority_queue<Node> q; for (int i = 1 ; i <= n; i++) dis[i] = INF, inS[i] = 0 ; for (auto k: spec){ dis[k] = 0 ; q.push ( (Node){0 , k} ); bs[k].set (func[k]); } while (!q.empty ()){ Node cur = q.top (); q.pop (); if (inS[cur.num]) continue ; inS[cur.num] = 1 ; for (int i = head[cur.num]; i; i = edge[i].nxt){ if ((LL)dis[edge[i].to] > (LL)dis[cur.num] + edge[i].dis){ bs[edge[i].to] = bs[cur.num]; dis[edge[i].to] = dis[cur.num] + edge[i].dis; q.push ( (Node){dis[edge[i].to], edge[i].to} ); } if ((LL)dis[edge[i].to] == (LL)dis[cur.num] + edge[i].dis) bs[edge[i].to] |= bs[cur.num]; } } } inline void init () { for (int i = 1 ; i <= n; i++){ bs[i].reset (); head[i] = 0 ; func[i] = 0 ; } edgeNum = 0 ; spec.clear (); } int main () { while (scanf ("%d%d%d%d" , &n, &m, &s, &q) != EOF){ init (); for (int i = 1 ; i <= m; i++){ int u, v, w; scanf ("%d%d%d" , &u, &v, &w); addEdge (u, v, w), addEdge (v, u, w); } for (int i = 1 ; i <= s; i++){ int x; scanf ("%d" , &x); spec.emplace_back (x); func[x] = i; } dijkstra (); while (q--){ int x; scanf ("%d" , &x); for (int i = 1 ; i <= s; i++) if (bs[x].test (i)) printf ("%d " , spec[i-1 ]); puts ("" ); } } return 0 ; }
hdu6085 Rikka with Candies 题目链接
用 bitset
记录 $A,B$ 数组中出现的数字(的奇偶性),倒序枚举 $k$,则 $B$ 中所有比 $k$ 大的数可能对答案有贡献,对这些数,统计它们的倍数,加上 $k$ 后与 $A$ 重叠部分就是对答案的贡献。
>folded 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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}const int N = 50005 ;int T, n, m, q, a[N], b[N], mxb, ans[N];bitset<N> A, B, MB; int main () { read (T); while (T--){ read (n, m, q); A.reset (), B.reset (), MB.reset (); mxb = 0 ; for (int i = 1 ; i <= n; i++){ read (a[i]); A.flip (a[i]); } for (int i = 1 ; i <= m; i++){ read (b[i]); B.flip (b[i]); mxb = max (mxb, b[i]); } for (int k = mxb; k >= 0 ; k--){ ans[k] = ((MB << k) & A).count () & 1 ; if (B.test (k)) for (int j = 0 ; j <= mxb; j += k) MB.flip (j); } while (q--){ int k; read (k); printf ("%d\n" , ans[k]); } } return 0 ; }
CF687C The Values You Can Make 题目链接
设 $dp[j][k]$ 表示凑出总数为 $j$ 的时候能否凑出 $k$,那么 $dp[j][k] = dp[j-a[i]][k]\ \mathrm{OR}\ dp[j-a[i]][k-a[i]]$. 用 bitset
优化。
复杂度:$O\left(\frac{nk^2}{32}\right)$
>folded 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 #include <bits/stdc++.h> using namespace std;template <typename T>void read (T&x) {x=0 ;int fl=1 ;char ch=getchar ();while (ch<'0' ||ch>'9' ){if (ch=='-' )fl=-1 ;ch=getchar ();}while (ch>='0' &&ch<='9' ){x=(x<<1 )+(x<<3 )+ch-'0' ;ch=getchar ();}x*=fl;} template <typename T,typename ...Args>inline void read (T&t,Args&...args) {read (t);read (args...);}typedef long long LL;const int N = 505 ;int n, k, a[N], id;bitset<N> dp[N<<1 ]; int main () { read (n, k); for (int i = 1 ; i <= n; i++) read (a[i]); dp[0 ].set (0 ); for (int i = 1 ; i <= n; i++) for (int j = k; j >= a[i]; j--) dp[j] |= dp[j-a[i]] | (dp[j-a[i]] << a[i]); printf ("%d\n" , (int )dp[k].count ()); for (int i = 0 ; i <= k; i++) if (dp[k].test (i)) printf ("%d " , i); puts ("" ); return 0 ; }