1. 程式人生 > >牛客國慶集訓派對Day2 A

牛客國慶集訓派對Day2 A

題目描述

深度學習演算法很大程度上基於矩陣運算。例如神經網路中的全連線,本質上是一個矩陣乘法;而卷積運算也通常是用矩陣乘法來完成的。有一些科研工作者為了讓神經網路的計算更快捷,提出了二值化網路的方法,就是將網路權重壓縮成只用兩種值表示的形式,這樣就可以用一些 trick 加速計算了。例如兩個二進位制向量點乘,可以用計算機中的與運算代替,然後統計結果中 1 的個數即可。 然而有時候為了降低壓縮帶來的誤差,只允許其中一個矩陣被壓縮成二進位制。這樣的情況下矩陣乘法運算還能否做進一步優化呢?給定兩個整數矩陣A, B,計算矩陣乘法 C = A x B。為了減少輸出,你只需要計算 C 中所有元素的的異或和即可。

輸入描述:

第一行有三個整數 N, P, M, 表示矩陣 A, B 的大小分別是 N x P, P x M 。
接下來 N 行是矩陣 A 的值,每一行有 P 個數字。第 i+1 行第 j 列的數字為 Ai,j, Ai,j 用大寫的16進製表示(即只包含 0~9, A~F),每個數字後面都有一個空格。
接下來 M 行是矩陣 B 的值,每一行是一個長為 P 的 01字串。第 i + N + 1 行第 j 個字元表示 Bj,i 的值。

輸出描述:

一個整數,矩陣 C 中所有元素的異或和。

示例1

輸入

複製

4 2 3
3 4
8 A
F 5
6 7
01
11
10

輸出

複製

2

說明

矩陣 C 的值為:
4 7 3
10 18 8
5 20 15
7 13 6

備註:

2 ≤ N, M ≤ 4096, 1 ≤ P ≤ 64, 0 ≤ Ai,j< 65536.

思路:

p最多64,那麼可將矩陣A的每一行縱向切割,最多切割8塊,矩陣B的每一列,橫向切割,最多切割8塊,矩陣B是01串,那麼每一列的每一塊的值就有256種可將矩陣A與矩陣B分塊後這256種情況相乘的結果先預處理求出來,再進行求最後答案。大概就是通過減小p值(矩陣分塊)來降低複雜度的吧~

程式碼如下:

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
#include<cmath>
#include<set>
#include<string>
#include<cstring>
#define ll long long
using namespace std;
const int N=4100;
int A[N][N],B[N][N];
int Ap[N][10][260],Bp[N][10];
int n,p,m;
int main(){
    char ch;
    scanf("%d%d%d",&n,&p,&m);
    for(int i=0;i<n;i++){
        for(int j=0;j<p;j++){
            scanf("%x",&A[i][j]);
        }
    }
    for(int i=0;i<p;i++){
        for(int j=0;j<m;j++){
            scanf("%1d",&B[j][i]);
        }
    }
    p=(p-1)/8+1;//矩陣B分成p塊
    
    //預處理A矩陣,將其分塊,並將每一塊對應的256種情況預處理出來
    //Ap[i][j][k]:=將第i行第j快與對應的k所代表的的8位二進位制塊相乘所得的結果
    for(int i=0;i<n;i++){
        for(int j=0;j<p;j++){
            int base=j*8;
            for(int k=0;k<256;k++){//對應矩陣B的分出的小塊的值
                for(int b=0;b<8;b++){
                    //1<<b表示B矩陣這一位上的數是1,如果對應的k值這一位上也是1
                    //說明Ap[i][j][k]的值需要加上A矩陣對應的值
                    if(k&(1<<b))Ap[i][j][k]+=A[i][base+b];
                }
            }
        }
    }
    //處理矩陣B,將其分塊,並將其每塊對應的二進位制串所對應的整數求出來
    for(int i=0;i<m;i++){
        for(int j=0;j<p;j++){
            int base=j*8;
            for(int k=0;k<8;k++){
                Bp[i][j]+=(B[i][base+k]<<k);
            }
        }
    }
    //利用預處理出來的結果,將c[i][j]所對應的塊的相乘的值加起來
    int ans=0,tmp;
    for(int i=0;i<n;i++){
        for(int j=0;j<m;j++){
            tmp=0;
            for(int k=0;k<p;k++){
                tmp+=Ap[i][k][Bp[j][k]];
            }
            ans^=tmp;
        }
    }
    printf("%d\n",ans);
}