常州模拟赛d8t1 友好数对

时间:2025-02-03 20:06:20

常州模拟赛d8t1 友好数对

分析:其实就是问你有多少对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 = ; int head[mod], to[mod], nextt[mod], tot, n, m, a[], b[],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] = ;
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 ;
} int main()
{
scanf("%d%d", &n, &m);
for (int i = ; i <= n; i++)
{
scanf("%d", &a[i]);
add(a[i]);
}
for (int i = ; i <= m; i++)
{
scanf("%d", &b[i]);
ans -= * query(b[i]);
}
tot = ;
for (int i = ; i <= n; i++)
head[a[i] % mod] = ;
for (int i = ; i <= n; i++)
for (int j = ; j < ; j++)
add(a[i] ^ ( << j));
for (int i = ; i <= m; i++)
for (int j = ; j < ; j++)
ans += query(b[i] ^ ( << j));
printf("%lld\n", ans / ); return ;
}