「BZOJ 3687」简单题

题目大意:给定一个长度为 $n$ 的序列 $a$,求所有子集和的异或和。$n \leq 1000, \sum a_i \leq 2 \times 10^6$

直接背包是 $O(n\sum a_i)$ 的,设 $f[i][j]$ 表示到第 $i$ 个数,$j$ 这个和出现了奇/偶数次,转移方程如下(当然可以省略第一维)

发现 $f$ 数组只有 $0,1$ 两个值,非常浪费,考虑用 $bitset$ 优化。

令 $bitset$ 的第 $i$ 位表示 $i$ 这个和出现了奇/偶次,设当前数字为 $x$,让 $bitset$ 异或一下右移 $x$ 位的状态即可。

#include <cstdio>
#include <bitset>
 
const int N = 2000005;
std::bitset<N> b; int n, x;
 
int main() {
    scanf("%d", &n);
    b[0] = 1;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &x);
        b ^= (b << x);
    }
    x = 0;
    for (int i = 1; i <= N; ++i)
        if (b[i]) x ^= i;
    printf("%d\n", x);
    return 0;
}

时间复杂度 $O(\sum a_i)$