题引
题解
朴素的算法 O(4096 * 64 * 4096) = O(1e9) 不用想是超时的。
因为每次矩阵乘法中存在很多重复的计算。
考虑将矩阵进行分块优化。预处理出每块的值。
怎么分块。考虑对A矩阵的列分块,和B矩阵的行分块。因为p是公共的边,且p <= 64
需要注意到的是 B矩阵中的取值仅有01那么如果对B矩阵进行分块的话。考虑每块8个01串。那么每一块的取值为[0,255]
于是我们预处理出A[i][j][0,255]的每种取值。i表示A矩阵的i行。j表示每行的第几块数。[0,255]表示当前块与所有01序列的取值。
A切完一共4096*8块,每块都预处理出256种情况,预处理的空间是4096*8*256,时间是4096*8*8*256。
那么在进行乘的时候就按照分好的块再去做乘法。时间为 4096 * 4096 * 8
代码
#include<bits/stdc++.h>
#define rep(i,a,n) for(int i=a;i<=n;i++)
using namespace std;
const int maxn = 4100;
int A[maxn][70],B[maxn][70];
int RA[maxn][10][260],RB[10][maxn];
char str[70];
int n,p,m;
inline void debug() {
rep(i,0,n-1) {
rep(j,0,p-1) printf("%d ",A[i][j]);
printf("\n");
}
rep(i,0,p-1) {
rep(j,0,m-1) printf("%d ",B[i][j]);
printf("\n");
}
}
inline void solve() {
memset(A,0,sizeof(A));
memset(B,0,sizeof(B));
memset(RA,0,sizeof(RA));
memset(RB,0,sizeof(RB));
rep(i,0,n-1) rep(j,0,p-1){
scanf("%s",str);int len = strlen(str),temp = 0;
rep(k,0,len-1) {
if(str[k] >= '0' && str[k] <= '9') temp = temp * 16 + str[k] - '0';
else temp = temp * 16 + str[k] - 'A' + 10;
}
A[i][j] = temp;
}
rep(i,0,m-1) {
scanf("%s",str);
rep(j,0,p-1) B[i][j] = str[j]-'0';
}
p = (p-1)/8+1; //将p进行分块,每8个一块
rep(i,0,n-1) rep(j,0,p-1) {
int base = j * 8;
rep(k,0,255) rep(l,0,7) if(k & (1<<l)) RA[i][j][k] += A[i][base+l];
}
rep(i,0,p-1) rep(j,0,m-1) {
int base = i * 8;
rep(l,0,7) RB[i][j] += (B[j][base+l] << l);
}
int res = 0;
rep(i,0,n-1) rep(j,0,p-1) rep(k,0,m-1) {
res ^= RA[i][j][RB[j][k]];
}
printf("%d\n",res);
}
int main()
{
while(~scanf("%d%d%d",&n,&p,&m)) {
solve();
//debug();
}
return 0;
}