Codeforces 165E Compatible Numbers(二进制+逆序枚举)
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.
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.
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.
2 90 36
36 90
4 3 6 3 6
-1 -1 -1 -1
5 10 6 9 8 2
-1 8 2 2 8
题目链接:Codeforces 165E
看到题目可以发现这题显然是要打表的,而且可以发现除了对应的1位必定要为0,其他位却是任意的,对每一个符合的数都去枚举任意一位可任意取值的位到底是0还是1,复杂度会变成指数级别,那么可以间接地进行递推,比如00 0110的一开始对应数字为11 1001,其他与00 0110对应数字符合xx x00x的形式,其中x表示可以任意取0或1,反正只要后面那两个1的位置为0即可,那么我们可以一位一位地慢慢枚举让哪一位变成,从xxxx x00x递推到0xxx x00x、x0xx xx0x、xx0x x00x、xxx0 x00x、xxxx 0x00x、……,一开始可能会想着这样会不会漏了其它不止变动一位的情况吧,但是实际上是不会的,这样往后推1位之后,后面的位只要让循环从大到小遍历,就会依次被枚举,即从0xxx x00x可以推到00xx x00x以至确定3位、4位的情况,当然我们是枚举把哪一位变成0,遇到已经是0的位就不用处理了,最后说一下为什么要从大到小,因为是枚举某一位$i$将其从1变成0,数字必定会减小$2^i$,因此是从大的数推到小的数,这样复杂度就只有几千万的循环了。
代码:
#include <stdio.h> #include <algorithm> #include <cstdlib> #include <cstring> #include <bitset> #include <string> #include <stack> #include <cmath> #include <queue> #include <set> #include <map> using namespace std; #define INF 0x3f3f3f3f #define LC(x) (x<<1) #define RC(x) ((x<<1)+1) #define MID(x,y) ((x+y)>>1) #define fin(name) freopen(name,"r",stdin) #define fout(name) freopen(name,"w",stdout) #define CLR(arr,val) memset(arr,val,sizeof(arr)) #define FAST_IO ios::sync_with_stdio(false);cin.tie(0); typedef pair<int, int> pii; typedef long long LL; const double PI = acos(-1.0); const int N = 1e6 + 7; const int M = 22; int arr[N]; int rev[1 << M]; int main(void) { int n, i, j; while (~scanf("%d", &n)) { int one = (1 << 22) - 1; CLR(rev, 0); for (i = 0; i < n; ++i) { scanf("%d", arr + i); int op = arr[i] ^ one; rev[op] = arr[i]; } for (i = one; i >= 0; --i) { if (rev[i]) { for (j = 0; j < M; ++j) { if (((i >> j) & 1) == 1)//i的对应位为1才需要变成0 { int v = i ^ (1 << j);//将i的第j位从1变成0 rev[v] = rev[i]; } } } } for (i = 0; i < n; ++i) printf("%d%c", rev[arr[i]] ? rev[arr[i]] : -1, " \n"[i == n - 1]); } return 0; }