// Strassen.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <vector>
using namespace std;
const int BFSZ = 20;
char fbuff[BFSZ];
template <class T>
T ** create(int n){
T ** mat = new T*[n];
for (int i=0;i<n;i++){
mat[i] = new T[n];
}
return mat;
}
template <class T>
void clear(T ** mat ,int n){
if (mat){
for (int i=0;i<n;i++){
delete [] mat[i];
}
delete [] mat;
}
}
template <class T>
void cp(T ** mat ,T ** src,int ax,int ay ,int bx,int by,int dem ){
int n = 1<<dem;
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
mat[ax+i][ay+j]=src[bx+i][by+j];
}
}
}
template <class T>
T ** add(T ** A, T ** B ,int ax,int ay ,int bx,int by,int dem,bool issub=false){
int n = 1<<dem;
T ** ret = create<T>(n);
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
if (issub){
ret[i][j]=A[ax+i][ay+j]-B[bx+i][by+j];
}else{
ret[i][j]=A[ax+i][ay+j]+B[bx+i][by+j];
}
}
}
return ret;
}
template <class T>
T ** mul(T ** A, T ** B ,int ax,int ay ,int bx,int by,int dem ){
T ** ret = create<T>(1<<dem);
if (dem==0){
ret[0][0]=A[ax][ay]*B[bx][by];
}else{
int subsz = 1<<(dem-1);
T ** t1 = add(A,A,ax,ay,(ax+subsz),(ay+subsz),dem-1);
T ** t2 = add(B,B,bx,by,(bx+subsz),(by+subsz),dem-1);
T ** m[8];
m[1] = mul(t1,t2,0,0,0,0,dem-1);
clear(t1,subsz);
clear(t2,subsz);
t1 = add(A,A,(ax+subsz),ay,(ax+subsz),(ay+subsz),dem-1);
m[2] = mul(t1,B,0,0,0,0,dem-1);
clear(t1,subsz);
t1 = add(B,B,bx,by+subsz,bx+subsz,by+subsz,dem-1,true);
m[3] = mul(A,t1,ax,ay,0,0,dem-1);
clear(t1,subsz);
t1 = add(B,B,bx+subsz,by,bx,by,dem-1,true);
m[4] = mul(A,t1,ax+subsz,ay+subsz,0,0,dem-1);
clear(t1,subsz);
t1 = add(A,A,ax,ay,ax,ay+subsz,dem-1);
m[5] = mul(t1,B,0,0,bx+subsz,by+subsz,dem-1);
clear(t1,subsz);
t1 = add(A,A,ax+subsz,ay,ax,ay,dem-1,true);
t2=add(B,B,bx,by,bx,by+subsz,dem-1);
m[6] = mul(t1,t2,0,0,0,0,dem-1);
clear(t1,subsz);
clear(t2,subsz);
t1 = add(A,A,ax,ay+subsz,ax+subsz,ay+subsz,dem-1,true);
t2 = add(B,B,bx+subsz,by,bx+subsz,by+subsz,dem-1);
m[7] = mul(t1,t2,0,0,0,0,dem-1);
T ** c[4];
c[0] = add(add( add(m[1],m[4],0,0,0,0,dem-1),m[5],0,0,0,0,dem-1,true),m[7],0,0,0,0,dem-1);
c[1] = add(m[3],m[5],0,0,0,0,dem-1);
c[2]= add(m[2],m[4],0,0,0,0,dem-1);
c[3] = add(add( add(m[1],m[2],0,0,0,0,dem-1,true),m[3],0,0,0,0,dem-1),m[6],0,0,0,0,dem-1);
cp(ret,c[0],0,0,0,0,dem-1);
cp(ret,c[1],0,subsz,0,0,dem-1);
cp(ret,c[2],subsz,0,0,0,dem-1);
cp(ret,c[3],subsz,subsz,0,0,dem-1);
for (int i=1;i<8;i++){ //没用 0
clear(m[i],subsz);
}
for (int i=0;i<4;i++){
clear(c[i],subsz);
}
}
return ret;
}
template <class T>
void init(T ** mat , int n){
for (int i=0;i<n;i++){
for (int j=0;j<n;j++){
cin>>mat[i][j];
}
}
}
template <class T>
void show(T ** mat , int n){
cout<<n<<endl;
for (int i=0;i<n;i++){
cout<<mat[i][0];
for (int j=1;j<n;j++){
cout<<" "<<mat[i][j];
}
cout<<endl;
}
}
int dem;
void work();
int _tmain(int argc, _TCHAR* argv[])
{
int cas=1;
for (int i=0;i<cas;i++){
sprintf(fbuff,"%d.in",i);
freopen(fbuff,"r",stdin);
sprintf(fbuff,"%d.out",i);
freopen(fbuff,"w",stdout);
work();
}
return 0;
}
void work(){
scanf("%d",&dem);
int n=1<<dem;
int ** A = create<int>(n);
init<int>(A ,n);
int ** B = create<int>(n);
init<int>(B , n);
int ** C = mul<int>(A,B,0,0,0,0,dem);
//int ** C = add<int>(A,B,0,0,0,0,dem);
show<int>(C,n);
}