CF165E
分析:
若 $s \& t = 0$,则肯定每一位是独立的,考虑第 $i$ 位:
-
$s_i = 0$,则 $t_i$ 可以为 $0$ 或 $1$;
-
$s_i = 1$,则 $t_i$ 必须为 $0$。
考虑把 $s_i$ 的 $0,1$ 对换:
-
$s_i = 1$,则 $t_i$ 可以为 $0$ 或 $1$;
-
$s_i = 0$,则 $t_i$ 必须为 $0$。
这可以发现,$t$ 是 $s$ 取反后的子集,故
在 $a_i$ 取反的子集中,看看有没有在 $a$ 数组里的即可。
做法:对于每个 $a_i$,把 $f[a_i] = i$,则
对于计算 $S$,在 $S$ 的子集中取最小值即可(一开始设为无穷大)。
注:若 $a_i$ 重复,取最小的 $i$。
代码:
#include <cstdio>
#include <iostream>
using namespace std;
const int N = 1e6 + 10, M = 22;
int f[1 << M], a[N];
int main() {
int n; scanf ("%d", &n);
for (int i = 0; i < (1 << M); ++i) {
f[i] = n + 1;
}
for (int i = 1; i <= n; ++i) {
scanf ("%d", &a[i]);
f[a[i]] = min (f[a[i]], i);
}
for (int i = 0; i < M; ++i) {
for (int j = 0; j < (1 << M); ++j) {
if ((1 << i) & j) f[j] = min (f[j], f[j - (1 << i)]);
}
} // 高维前缀和求子集
for (int i = 1; i <= n; ++i) {
int x = (1 << M) - 1 - a[i]; // x 为 a[i] 取反后的结果
printf ("%d ", (f[x] == n + 1) ? -1 : a[f[x]]);
}
return 0;
}
浙公网安备 33010602011771号