CCPC-WannaFly-Camp #5A矩阵乘法 【分块】

1082: 矩阵乘法 时间限制: 2 Sec 内存限制: 128 MB 提交: 97 解决: 6 [提交][状态][讨论版][命题人:admin]

题目描述
深度学习算法很大程度上基于矩阵运算。例如神经网络中的全连接本质上是一个矩阵乘法,而卷积运算也通常是用矩阵乘法来实现的。有一些科研工作者为了让神经网络的计算更快捷,提出了二值化网络的方法,就是将网络权重压缩成只用两种值表示的形式,这样就可以用一些 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;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值