Acdream Xor 简单数学
给定一个集合A,一个集合B,A,B元素个数相等,然后问是否存在一个数X使得A中的元素均与这个数进行按位异或操作后的结果为B集合,如果存在输出最小的数,不存在输出-1。
思路:由于给定的N为奇数,所以能够根据二进制位的最右边位确定唯一的分组,然后只需要判定这个分组是否合理即可。
分组是这样划分的,如有A、B两组数据,把A组根据末位0和1分成两组,B组同理划分,那么只有00配对或者是01配对,这有各组中数的个数确定。配对模式确定后,再通过30次判定即可。
#include <cstdlib> #include <cstdio> #include <iostream> #include <cstring> #include <cstdio> #include <cstdlib> using namespace std; const int MaxN = 100005; int a[MaxN], b[MaxN], N; int ans[40]; int st[4][MaxN]; int cnt[4], bit[4][40]; // N是奇数就好做了 int cal(int x, int b[]) { for (int i = 0; i < 30; ++i) { if ((x >> i) & 1) ++b[i]; } } int judge(int i, int mode) { // 如果是模式0,即st0 与 st2 匹配 if (mode == 0) { if (bit[0][i] == bit[2][i] && bit[1][i] == bit[3][i]) return 0; else if (bit[0][i] == cnt[2]-bit[2][i] && bit[1][i] == cnt[3]-bit[3][i]) return 1; else return -1; } else { // 如果是模式1,即st0 与 st3匹配 if (bit[0][i] == bit[3][i] && bit[1][i] == bit[2][i]) return 0; else if (bit[0][i] == cnt[3]-bit[3][i] && bit[1][i] == cnt[2]-bit[2][i]) return 1; else return -1; } } void gao() { for (int i = 0; i < 4; ++i) { memset(st[i], 0, sizeof (st[i])); memset(bit[i], 0, sizeof (bit[i])); } memset(ans, 0, sizeof (ans)); memset(cnt, 0, sizeof (cnt)); for (int i = 0; i < N; ++i) { if (!(a[i] & 1)) st[0][cnt[0]++] = i; else st[1][cnt[1]++] = i; if (!(b[i] & 1)) st[2][cnt[2]++] = i; else st[3][cnt[3]++] = i; } for (int i = 0; i < 4; ++i) { for (int j = 0; j < cnt[i]; ++j) { if (i < 2) cal(a[st[i][j]], bit[i]); else cal(b[st[i][j]], bit[i]); } } int mode = -1; // 由最低位的1的个数划分模式,由于N为奇数,所以划分的方式是唯一的 if (cnt[0] == cnt[2]) ans[0] = mode = 0; else if (cnt[0] == cnt[3]) ans[0] = mode = 1; if (mode == -1) { puts("-1"); return; } for (int i = 1; i < 30; ++i) { ans[i] = judge(i, mode); if (ans[i] == -1) { puts("-1"); return; } } int ret = 0; for (int i = 0; i < 30; ++i) { ret += ans[i] ? (1 << i) : 0; } printf("%d\n", ret); } int main() { while (scanf("%d", &N) == 1) { for (int i = 0; i < N; ++i) { scanf("%d", &a[i]); } for (int i = 0; i < N; ++i) { scanf("%d", &b[i]); } gao(); } return 0; }