共现的数
Description
给出n个包含整数的集合,当两个整数至少同时出现在一个集合中时我们认为两个整数存在共现关系.给定两个整数x、y,我们需要计算有多少个不同的整数同时和x、y存在共现关系.
Input
包含不超过10组测试数据.
每组测试数据的第一行包含一个整数n,表示一共有n个集合.
接下来n行依次描述的这n个集合,每行第一个整数mi表示集合中整数的数量,接下来mi个正整数表示该集合中的各个元素.
接下来一行包含一个整数q,表示接下来有q次询问.
每个询问占一行,包含两个整数x、y.
数据保证x和y均至少在一个集合中出现过.
1 ≤ n ≤ 50
1 ≤ mi ≤ 500
1 ≤ q ≤ 500
集合中的整数不大于104
Output
对于每次询问,输出有多少个不为x或y且不同的整数同时和x、y存在共现关系.
Sample Input
3
3 1 2 3
4 1 3 4 5
3 2 5 6
5
1 2
1 3
2 4
1 5
5 6
Sample Output
2
3
3
3
1
Hint
同时和1、2共现的整数为:3、5
同时和1、3共现的整数为:2、4、5
同时和2、4共现的整数为:1、3、5
同时和1、5共现的整数为:2、3、4
同时和5、6共现的整数为:2
分析
本题数据十分的大,如果正常做法时间复杂度是O(n),所以用二进制进行优化
代码
#include<bits/stdc++.h>
using namespace std;
const int N = 1e4 + 10;
int a[N];
int n;
long long mp[N][250];
void solve(){
for(int i = 1; i <= n; i++){
int l;
cin >> l;
for(int j = 1; j <= l; j++){
cin >> a[j];
}
for(int j = 1; j <= l; j++){
int temp = a[j] / 50, temp1 = a[j] % 50;
for(int k = 1; k <= l; k++){
mp[a[k]][temp] |= 1ll << (temp1);
}
}
}
int q;
cin >> q;
for(int i = 1; i <= q; i++){
int x, y;
cin >> x >> y;
int ans = 0;
int temp = x / 50, temp1 = x % 50;
int temp2 = y / 50, temp3 = y % 50;
for(int i = 0; i <= 1e4; i++){
if(i == x || i == y){
continue;
}
if((mp[i][temp] & (1ll << (temp1))) && (mp[i][temp2] & (1ll << (temp3)))){
// cout << i << "\n";
ans ++;
}
}
cout << ans << "\n";
}
for(int i = 0; i <= 1e4; i++){
for(int j = 0; j < 205; j++){
mp[i][j] = 0;
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(0);
cout.tie(0);
int t = 1;
// cin >> t;
while(cin >> n){
solve();
}
return 0;
}