CF165E

分析:

若 $s \& t = 0$,则肯定每一位是独立的,考虑第 $i$ 位:

  1. $s_i = 0$,则 $t_i$ 可以为 $0$ 或 $1$;

  2. $s_i = 1$,则 $t_i$ 必须为 $0$。

考虑把 $s_i$ 的 $0,1$ 对换:

  1. $s_i = 1$,则 $t_i$ 可以为 $0$ 或 $1$;

  2. $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;
}
posted @ 2022-03-29 16:51  wangzhongyuan  阅读(15)  评论(0)    收藏  举报  来源