牛客练习赛77 D-小G的LY数对 思维+Hash
传送门: https://ac.nowcoder.com/acm/contest/11160/D
题意
小G定义LY数对为两个数x,y在二进制的异或操作后恰好有两位是1
小G现在有两个数组a,b长度分别为n,m
现在小G想知道有多少对i,j满足
(1<=i<=n,1<=j<=m)满足a[i]和b[j]是LY数对
思路
如
果
是
暴
力
枚
举
a
[
i
]
的
同
时
暴
力
枚
举
两
个
位
置
上
的
数
,
复
杂
度
为
O
(
3
0
2
n
)
。
如果是暴力枚举a[i]的同时暴力枚举两个位置上的数,复杂度为O(30^2n)。
如果是暴力枚举a[i]的同时暴力枚举两个位置上的数,复杂度为O(302n)。
必
然
会
T
,
怎
么
办
能
把
其
中
一
个
30
变
小
呢
?
直
到
复
杂
度
在
O
(
1
e
8
)
之
内
?
必然会T,怎么办能把其中一个30变小呢?直到复杂度在O(1e8)之内?
必然会T,怎么办能把其中一个30变小呢?直到复杂度在O(1e8)之内?
我 们 知 道 题 目 的 意 思 是 x ⨁ y = 两 位 2 次 方 数 相 加 = ( 1 < < i ) ⨁ ( 1 < < j ) . ( i ! = j ) 我们知道题目的意思是x \bigoplus y=两位2次方数相加=(1<<i)\bigoplus (1<<j).(\red{i!=j}) 我们知道题目的意思是x⨁y=两位2次方数相加=(1<<i)⨁(1<<j).(i!=j)
转
化
为
x
⨁
(
1
<
<
i
)
=
y
⨁
(
1
<
<
j
)
.
(
i
!
=
j
)
转化为x\bigoplus (1<<i)=y\bigoplus (1<<j).(\red{i!=j})
转化为x⨁(1<<i)=y⨁(1<<j).(i!=j)
转
化
为
x
⨁
(
1
<
<
j
)
=
y
⨁
(
1
<
<
i
)
.
(
i
!
=
j
)
转化为x\bigoplus (1<<j)=y\bigoplus (1<<i).(\red{i!=j})
转化为x⨁(1<<j)=y⨁(1<<i).(i!=j)
所
以
我
们
可
以
通
过
这
个
。
所以我们可以通过这个。
所以我们可以通过这个。
枚
举
i
,
H
a
s
h
保
存
所
有
的
a
x
⨁
(
1
<
<
i
)
.
枚举i,Hash保存所有的a_x\bigoplus (1<<i).
枚举i,Hash保存所有的ax⨁(1<<i).
枚
举
j
所
有
的
b
y
⨁
(
1
<
<
j
)
,
查
找
是
否
有
和
它
相
等
的
数
,
a
n
s
+
个
数
。
枚举j所有的b_y\bigoplus (1<<j),查找是否有和它相等的数,ans+个数。
枚举j所有的by⨁(1<<j),查找是否有和它相等的数,ans+个数。
$$
可
是
我
们
之
前
说
过
i
!
=
j
,
所
以
要
提
前
减
掉
这
个
i
=
=
j
的
情
况
。
可是我们之前说过\red{i!=j},所以要提前减掉这个i==j的情况。
可是我们之前说过i!=j,所以要提前减掉这个i==j的情况。
i
=
=
j
必
然
x
=
=
y
,
所
以
减
掉
x
=
=
y
的
数
量
即
可
。
i==j必然x==y,所以减掉x==y的数量即可。
i==j必然x==y,所以减掉x==y的数量即可。
总 时 间 复 杂 度 为 O ( 30 n ∗ C ) , C 是 一 个 小 于 30 的 常 数 。 总时间复杂度为O(30n*C),C是一个小于30的常数。 总时间复杂度为O(30n∗C),C是一个小于30的常数。
Code(690MS)
#include "bits/stdc++.h"
using namespace std;
typedef long long ll;
const int N = 1e7 + 7;
const int mod = 1e6 + 7;
struct Hash {
int v, next, w;
}e[N];
int head[N], cnt;
void Insert(int x) {
int u = x % mod;
for(int i = head[u]; ~i; i = e[i].next) {
if(e[i].v == x) {
e[i].w++;
return ;
}
}
e[cnt] = Hash{x, head[u], 1};
head[u] = cnt++;
}
int get(int x) {
int u = x % mod;
for(int i = head[u]; ~i; i = e[i].next) {
if(e[i].v == x) {
return e[i].w;
}
}
return 0;
}
map<int, int> mp;
void solve() {
mem(head, -1);
int n, m; cin >> n >> m;
vector<int> a(n + 1), b(m + 1);
for(int i = 1;i <= n; i++) cin >> a[i], mp[a[i]]++;
ll res = 0;
for(int i = 1;i <= m; i++) {
cin >> b[i];
res += mp[b[i]] * 30;
}
for(int i = 1;i <= n; i++) {
for(int k = 0;k < 30; k++) {
Insert(a[i] ^ (1ll << k));
}
}
ll ans = 0;
for(int i = 1;i <= m; i++) {
for(int k = 0;k < 30; k++) {
ans += get(b[i] ^ (1ll << k));
}
}
cout << (ans - res) / 2 << endl;
}
signed main() {
solve();
}