分析:其实就是问你有多少对a,b有且仅有两位不相同.我们可以先枚举这两位,对应ai枚举一位,对应bi枚举一位,如果ai^(1<<x) == bi^(1<<y),证明恰好有两位不一样,那么ans++.
考虑怎么快速地得出答案,我们可以用一个数组记录ai^(1<<x)出现了多少次,但是因为ai,bi可能有2^30存不下,所以要用到hash表。数据中给定的ai,bi可能有相等的,这个在后面的计算中每一位都会被重复计算一次,为了方便起见,我们规定所有数的位数都是30位,不够就补0,所以查询到有多少个ai与bi相等,就减30*个数.最后在输出答案的时候要除以2,因为如果a的第三位和b的第五位异或1后ab相同,a的第五位和b的第三位异或1后ab相同,那么(a,b)数对就会被计算两次,实际上应该只被计算一次.所以要除以2。
不要忘了在第一次用完链表后清空链表.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #include <queue> using namespace std; const int mod = 10000019; int head[mod], to[mod], nextt[mod], tot, n, m, a[100010], b[100010],num[mod]; long long ans; void add(int x) { int t = x % mod; for (int i = head[t]; i; i = nextt[i]) { if (to[i] == x) { num[i]++; return; } } to[++tot] = x; num[tot] = 1; nextt[tot] = head[t]; head[t] = tot; } int query(int x) { int t = x % mod; for (int i = head[t]; i; i = nextt[i]) if (to[i] == x) return num[i]; return 0; } int main() { scanf("%d%d", &n, &m); for (int i = 1; i <= n; i++) { scanf("%d", &a[i]); add(a[i]); } for (int i = 1; i <= m; i++) { scanf("%d", &b[i]); ans -= 30 * query(b[i]); } tot = 0; for (int i = 1; i <= n; i++) head[a[i] % mod] = 0; for (int i = 1; i <= n; i++) for (int j = 0; j < 30; j++) add(a[i] ^ (1 << j)); for (int i = 1; i <= m; i++) for (int j = 0; j < 30; j++) ans += query(b[i] ^ (1 << j)); printf("%lld ", ans / 2); return 0; }