P16519 [GKS 2015 #E] Robot Rock Band 题解
题目大意
有 \(T\) 组测试用例,每组测试用例给定四个列表 \(A\),\(B\),\(C\),\(D\),每个列表包含 \(N\) 个数字,问有多少种方式从四个列表中各选一个数使异或和为 \(K\)。
思路分析
这题看似要用 \(O(n^4)\) 的时间复杂度过,但这样会超时,所以我们要另寻出路。
我们设从 \(A\) 列表拿的数为 \(a\),从 \(B\) 列表拿的数为 \(b\),从 \(C\) 列表拿的数为 \(c\),从 \(D\) 列表拿的数为 \(d\),那么 \(a\bigoplus b\bigoplus c\bigoplus d=K\),然后我们将这个式子转移一下就变成这样 \(a\bigoplus b=K\bigoplus c\bigoplus d\)。
这样问题就简单多了,相当于求从 \(A\),\(B\),\(C\),\(D\) 中各拿一个数,使 \(a\),\(b\) 的异或和等于 \(k\),\(c\),\(d\) 的异或和。
转换完之后解法就出来了,我们先处理出 \(A\),\(B\) 拿出的数的异或值的所有可能,用一个键值对来表示每种异或值会出现几次。
然后枚举 \(C\),\(D\) 拿出的数和 \(K\) 的异或值的所有可能,对应的 \(a\bigoplus b\) 的出现次数全部加起来就是答案。时间复杂度 \(O(n^2)\)。
#include<bits/stdc++.h>
using namespace std;
const int N=1e3+5;
unordered_map<long long,long long> mp;
long long a[N],b[N],c[N],d[N];//因为数据较大,所以要开long long
int main(){
std::ios::sync_with_stdio(0);
cin.tie(0),cout.tie(0);
int T;
cin>>T;
for(int id=1;id<=T;id++){
mp.clear();
int n;
long long k;
cin>>n>>k;
for(int i=1;i<=n;i++){
cin>>a[i];
}
for(int i=1;i<=n;i++){
cin>>b[i];
}
for(int i=1;i<=n;i++){
cin>>c[i];
}
for(int i=1;i<=n;i++){
cin>>d[i];
}
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
mp[a[i]^b[j]]++;//统计出现次数
}
}
long long ans=0;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
ans+=mp[k^c[i]^d[j]];//统计答案
}
}
cout<<"Case #"<<id<<": "<<ans<<'\n';
}
return 0;
}

浙公网安备 33010602011771号