题目描述
深度学习算法很大程度上基于矩阵运算。例如神经网络中的全连接本质上是一个矩阵乘法,而卷积运算也通常是用矩阵乘法来实现的。有一些科研工作者为了让神经网络的计算更快捷,提出了二值化网络的方法,就是将网络权重压缩成只用两种值表示的形式,这样就可以用一些 trick 加速计算了。例如两个二进制向量点乘,可以用计算机中的与运算代替,然后统计结果中 1 的个数即可。
然而有时候为了降低压缩带来的误差,只允许其中一个矩阵被压缩成二进制。这样的情况下矩阵乘法运算还能否做进一步优化呢?给定一个整数矩阵 和一个二值矩阵,计算矩阵乘法 。为了减少输出,你只需要计算 中所有元素的的异或和即可。
输入
第一行有三个整数 , 表示矩阵 的大小分别是 。
接下来 行是矩阵 的值,每一行有 个数字。第 行第 列的数字为 , 用大写的16进制表示(即只包含 0~9, A~F),每个数字后面都有一个空格。
接下来 行是矩阵 的值,每一行是一个长为 的 01字符串。第 行第 个字符表示 的值。
输出
一个整数,矩阵 中所有元素的异或和。
样例输入
4 2 3
3 4
8 A
F 5
6 7
01
11
10
样例输出
2
提示
数据范围
2 <= N,M <= 4096 , 1<=P <=64 , 0<=Aij<=65536, 0<=Bij<=1
样例解释
矩阵 的值为:
4 7 3
10 18 8
5 20 15
7 13 6
题解 分块
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
using namespace std;
#define PI 3.1415926
#define sc(a) scanf("%d",&a)
#define pfs(a) printf("%d ",a)
#define pfn(a) printf("%d\n",a);
#define pfln(a) printf("%lld\n",a);
#define rep(i,a,n) for(int i = a; i < n; i++)
#define per(i,a,n) for(int i = n-1; i >= a; i--)
#define mem(a,x) memset(a,x,sizeof(a))
typedef long long LL;
typedef pair<int,int> P;
const int maxn = 4100; //不能开5000会MLE
const int maxp = 80;
const int mod = 1e9+7;
const int INF = 1e9+1;
int n,p,m;
int a[maxn][maxp],b[maxn][maxp],c[maxn][maxn];
int Ap[maxn][10][260],Bp[maxn][10];
int main()
{
sc(n),sc(p),sc(m);
rep(i,0,n) rep(j,0,p)
scanf("%x",&a[i][j]);
rep(i,0,m)
{
string s;
cin >> s;
rep(j,0,p)
b[i][j] = s[j]-'0';
}
p = (p-1)/8 + 1; //总共最多为64,分成8快,每块8个数字,共2^8 = 256种情况
//处理A矩阵,将其分块,并将其每块对应的256中情况预处理出来,
//A[i][j][k] 表示第i行第j块对与k所代表的8位二进制块相乘所得结果
rep(i,0,n)
rep(j,0,p)
{
int base = j*8;
rep(k,0,256)
rep(l,0,8)
{
if(k&(1<<l)) Ap[i][j][k] += a[i][base+l];
//cout << ( k &(1<<l) ) << endl;
}
}
//处理B矩阵,将其分块,并将其每块对应的二进制串所对应的整数统计出来
//B[i][j] 表示第i列第j块所对应的整数
rep(i,0,m)
rep(j,0,p)
{
int base = j*8;
rep(k,0,8)
Bp[i][j] += b[i][base+k]<<k;
}
//利用预处理出来的数组,将c[i][j] 所对应的块的相乘的值加起来
rep(i,0,n)
rep(j,0,m)
rep(k,0,p)
c[i][j] += Ap[i][k][Bp[j][k]];
int ans = 0;
rep(i,0,n)
rep(j,0,m)
{
//cout << c[i][j] << endl;
ans ^= c[i][j];
}
pfn(ans);
return 0;
}