Compatible Numbers
time limit per test:4 seconds
memory limit per test:256 megabytes
input:standard input
output:standard output
Two integers x and y are compatible, if the result of their bitwise “AND” equals zero, that is, a & b = 0. For example, numbers 90 (10110102) and 36 (1001002) are compatible, as 10110102 & 1001002 = 02, and numbers 3 (112) and 6 (1102) are not compatible, as 112 & 1102 = 102.
You are given an array of integers a1, a2, …, an. Your task is to find the following for each array element: is this element compatible with some other element from the given array? If the answer to this question is positive, then you also should find any suitable element.
Input
The first line contains an integer n (1 ≤ n ≤ 106) — the number of elements in the given array. The second line contains n space-separated integers a1, a2, …, an (1 ≤ ai ≤ 4·106) — the elements of the given array. The numbers in the array can coincide.
Output
Print n integers ansi. If ai isn’t compatible with any other element of the given array a1, a2, …, an, then ansi should be equal to -1. Otherwise ansi is any such number, that ai & ansi = 0, and also ansi occurs in the array a1, a2, …, an.
Examples
input
2
90 36
output
36 90
input
4
3 6 3 6
output
-1 -1 -1 -1
input
5
10 6 9 8 2
output
-1 8 2 2 8
Tips
题意:
n n n 个正整数 a [ 1.. n ] a[1..n] a[1..n] ,满足 1 ⩽ a i ⩽ 4 × 1 0 6 1 \leqslant a_i \leqslant 4\times10^6 1⩽ai⩽4×106 ,请你对每个数都进行判断:其他数中是否存在和该数的与操作为 0 0 0 的数。若存在,则输出那个数,否则输出 − 1 -1 −1 。
题解:
队友写过一回,觉得此题不错,收藏了。
该解法使用另一个数组 b [ i ] b[i] b[i] 保存与 i i i 按位与得 0 0 0 的数(且这个数在 a [ 1.. n ] a[1..n] a[1..n] 中出现)。
我们先设想一个最严苛的条件让两个数按位与得 0 0 0 ,即,两个数所有的位都相反。
而通过分析数据范围,我们知道, 2 21 < 4 × 1 0 6 < 2 22 2^{21} <4\times10^6<2^{22} 221<4×106<222 ,因此,可以取上界为 2 22 2^{22} 222 ,这样一来,一个数 i i i 的按位取反的数即为 2 22 − i 2^{22}-i 222−i (原本为 0 0 0 的, 1 1 1 减 0 0 0 得 1 1 1 ;为 1 1 1 的, 1 1 1 减 1 1 1 得 0 0 0),记作 i − i^{-} i−。
初始情况即为, b [ ] b[] b[] 中保存了所有的 a [ i ] − a[i]^- a[i]− 。然后,我们再通过缓和条件逐步找到所有 i i i 对应的 b [ i ] b[i] b[i] 。
为了缓和条件,我们先来分析一下
b
[
i
]
b[i]
b[i] 和
i
i
i 的关系(任意时刻),由定义出发,
i
i
i 中的某一位如果为
1
1
1 则
b
[
i
]
b[i]
b[i] 中的对应位置必为
0
0
0 ,否则任意。因此,将
i
i
i 中某些位的
0
0
0 变成
1
1
1 ,得到的新数
j
j
j ,和
i
i
i 共享一个
b
[
i
]
b[i]
b[i] 。而易知
j
>
i
j>i
j>i ,因此需要从大到小去缓和条件。具体操作的时候,可以粗略地判断 b[i|1<<j]
是否有值,对时间复杂度不会有太大影响。
最后,只需看 b [ a [ i ] ] b[a[i]] b[a[i]] 是否有值即可。
Reference Code
#include <cstdio>
const int INF=(1<<22)-1;
const int MAXN=1e6+10;
int a[MAXN],b[INF+10];
int n;
int main(){
scanf("%d",&n);
for (int i=0;i<n;++i){
scanf("%d",&a[i]);
b[INF-a[i]]=a[i];
}
for (int i=INF;i>=0;--i){
if (b[i]) continue;
for (int j=0;j<22;++j){
if (!b[i|1<<j]) continue;
b[i]=b[i|1<<j];
break;
}
}
for (int i=0;i<n;++i)
printf("%d%s",b[a[i]]?b[a[i]]:-1,i<n-1?" ":"\n");
return 0;
}