就是让你做一个矩阵乘法,但是可能暴力做复杂度比较高(不会告诉你暴力也能过)。
题目已经大致告诉你优化的方法了。如果两个二进制向量点乘,那么可以用与运算代替乘法运算,最后统计结果中1的个数。而本题就是让你实现这个过程。
可以看到,第二个矩阵是一个01矩阵,所以说可以用类似的方法。第一个矩阵是一个16进制的矩阵,但是我们可以把这个16进制的2^16级别的数字拆成16个矩阵。而第二个矩阵我们也可以看作16个相同的矩阵。这里第0~15个矩阵分别对应第0~15位,也即2的对应次方。如此拆分之后,就变成了16个01矩阵相乘,并且不用考虑进位。
由于是01矩阵,根据矩阵乘法的定义,结果矩阵的某一个位置(i,j),相当于第一个矩阵的第i行和第二个矩阵的第j列相乘。这也就是两个01向量的点乘,恰好本题的p的大小为64,所有每一个向量可以用一个unsigned long long来存下。于是相乘就可以转化为两个向量对应的数字的按位与,最后看结果有多少个1,再乘以对应2的幂,就是这一位对最后答案的贡献。这样计算最多16次即可,复杂度是O(16*NM)。具体见代码:
#include <bits/stdc++.h>
#define LL long long
#define ULL unsigned LL
using namespace std;
ULL a[16][4096],b[16][4096];
int n,m,p;
int main()
{
char s[100];
scanf("%d%d%d",&n,&p,&m);
for(int i=0;i<n;i++)
for(int j=0;j<p;j++)
{
int x;
scanf("%x",&x);
for(int k=0;k<=15;k++)
if (x&(1<<k)) a[k][i]|=(1ULL<<j);
}
for(int i=0;i<m;i++)
{
ULL x=0;
scanf("%s",s);
for(int j=0;j<p;j++)
if (s[j]=='1') x|=(1ULL<<j);
for(int j=0;j<16;j++) b[j][i]=x;
}
int ans=0;
for(int i=0;i<n;i++)
for(int j=0;j<m;j++)
{
int res=0;
for(int k=0;k<16;k++)
res+=(1<<k)*__builtin_popcountll(a[k][i]&b[k][j]);
ans^=res;
}
printf("%d\n",ans);
return 0;
}