Problem:
Problem K: Gold Rush
Problem
moritaoy君とは、コンピュータのなかで暮らしている謎の大学生です。
moritaoy君が暮らしている区画は、縦に $2^H$ 、横に $2^W$ 、の大きさのある二次元空間 $S= \{ (p,q) \in \mathbb{Z}^2 | 0 \leq p \lt 2^H, 0 \leq q \lt 2^W  \} $ として表されます。
moritaoy君はいくつかの非負整数を要素とする二次元ベクトルを持っていて、この空間上を足し算を用いて移動します。
moritaoy君が $(a,b)$ にいて、ベクトル $(i,j)$ によって移動するとは、具体的には以下のような行動を示します。
$(a+i,b+j)$ に移動する。ただし、そのような点が $S$ に存在しない場合は、オーバーフローを起こし、$a+i \equiv k \bmod 2^H , b+j \equiv l \bmod 2^W$ を満たすようなmoritaoy君の暮らす空間上の点 $(k,l) \in S$ に移動する。
以下がmoritaoy君の一日の予定です。
一日を開始する。このとき、moritaoy君は $(0,0)$ にいて、疲労度は $0$ である。2.を行う。
今日、moritaoy君が移動を行った回数が $K$ 以上なら4.を、そうでないなら3.か4.のどちらか一方を行う。
moritaoy君が持っているベクトルのなかから一つを選び、これを $v$ とする。$v$ によって移動する。moritaoy君の疲労度が $T_v$ 増加する。その後のmoritaoy君の疲労度を $T$ とし、 $T \times G_v$ 単位時間休憩する。2.を行う。
一日を終了する。
moritaoy君は、色々な予定を立てて遊ぶことにしました。
各 $(a,b)$ に対して、一日を終了したときにmoritaoy君が $(a,b)$ にいるような予定全ての、一日に休憩する時間の総和を求めてください。
ただし、二つの予定が異なるとは、二つの予定の一日に移動する回数が異なる、またはある $i$ があって $i$ 回目の移動に用いるベクトルが異なることをいいます。
Input
入力は以下の形式で与えられる。
$H$ $W$ $K$
$T_{(0,0)}$ $\ldots$ $T_{(0,2^W-1)}$
$\vdots$
$T_{(2^H-1,0)}$ $\ldots$ $T_{(2^H-1,2^W-1)}$
$G_{(0,0)}$ $\ldots$ $G_{(0,2^W-1)}$
$\vdots$
$G_{(2^H-1,0)}$ $\ldots$ $G_{(2^H-1,2^W-1)}$
$T_{(i,j)}$ が $-1$ でないとき、かつそのときに限り、moritaoy君はベクトル $(i,j)$ を持つ。
$2^H \leq i$ または $2^W \leq j$ ならばmoritaoy君はベクトル $(i,j)$ を持たない。
Constraints
入力は以下の条件を満たす。
$0 \leq H,W \leq 9$
$1 \leq K \leq 10^{5}$
$-1 \leq T_{(i,j)} \lt 998244353$
$-1 \leq G_{(i,j)} \lt 998244353$
$T_{(i,j)}=-1$ のとき、かつそのときに限り、$G_{(i,j)}=-1$
入力は全て整数である
Output
出力は $2^H$ 行からなる。
$i$ 行目には $2^W$ 個の要素を空白区切りで出力する。
$i$ 行目の $j$ 番目の要素は、一日を終了したときにmoritaoy君が $(i-1,j-1)$ にいるような予定全ての、一日に休憩する時間の総和である。
ただし、答えは非常に大きくなることがあるので、$998244353$ で割ったあまりを出力すること。
Sample Input 1
0 0 10
1
2
Sample Output 1
440
Sample Input 2
1 2 2
1 2 3 4
5 6 7 0
9 8 7 6
1 3 3 3
Sample Output 2
355 358 363 386
391 408 419 378
Sample Input 3
1 1 100000
900000000 -1
-1 902010312
218738721 -1
-1 281371299
Sample Output 3
311157817 0
0 640524124

Submitted solutions:

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


template<typename T,T MOD = 1000000007>
struct Mint{
  static constexpr T mod = MOD;
  T v;
  Mint():v(0){}
  Mint(signed v):v(v){}
  Mint(long long t){v=t%MOD;if(v<0) v+=MOD;}

  Mint pow(long long k){
    Mint res(1),tmp(v);
    while(k){
      if(k&1) res*=tmp;
      tmp*=tmp;
      k>>=1;
    }
    return res;
  }

  static Mint add_identity(){return Mint(0);}
  static Mint mul_identity(){return Mint(1);}

  Mint inv(){return pow(MOD-2);}

  Mint& operator+=(Mint a){v+=a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator-=(Mint a){v+=MOD-a.v;if(v>=MOD)v-=MOD;return *this;}
  Mint& operator*=(Mint a){v=1LL*v*a.v%MOD;return *this;}
  Mint& operator/=(Mint a){return (*this)*=a.inv();}

  Mint operator+(Mint a) const{return Mint(v)+=a;};
  Mint operator-(Mint a) const{return Mint(v)-=a;};
  Mint operator*(Mint a) const{return Mint(v)*=a;};
  Mint operator/(Mint a) const{return Mint(v)/=a;};

  Mint operator-() const{return v?Mint(MOD-v):Mint(v);}

  bool operator==(const Mint a)const{return v==a.v;}
  bool operator!=(const Mint a)const{return v!=a.v;}
  bool operator <(const Mint a)const{return v <a.v;}

  // find x s.t. a^x = b
  static T log(T a,T b){
    const T sq=40000;
    unordered_map<T, T> dp;
    dp.reserve(sq);
    Mint res(1);
    for(int r=0;r<sq;r++){
      if(!dp.count(res.v)) dp[res.v]=r;
      res*=a;
    }
    Mint p=Mint(a).inv().pow(sq);
    res=b;
    for(int q=0;q<=MOD/sq+1;q++){
      if(dp.count(res.v)){
        T idx=q*sq+dp[res.v];
        if(idx>0) return idx;
      }
      res*=p;
    }
    assert(0);
    return T(-1);
  }

  static Mint comb(long long n,int k){
    Mint num(1),dom(1);
    for(int i=0;i<k;i++){
      num*=Mint(n-i);
      dom*=Mint(i+1);
    }
    return num/dom;
  }
};
template<typename T,T MOD> constexpr T Mint<T, MOD>::mod;
template<typename T,T MOD>
ostream& operator<<(ostream &os,Mint<T, MOD> m){os<<m.v;return os;}


constexpr int bmds(int x){
  const int v[] = {1012924417, 924844033, 998244353,
                   897581057, 645922817};
  return v[x];
}
constexpr int brts(int x){
  const int v[] = {5, 5, 3, 3, 3};
  return v[x];
}

template<int X>
struct NTT{
  static constexpr int md = bmds(X);
  static constexpr int rt = brts(X);
  using M = Mint<int, md>;
  vector< vector<M> > rts,rrts;

  void ensure_base(int n){
    if((int)rts.size()>=n) return;
    rts.resize(n);rrts.resize(n);
    for(int i=1;i<n;i<<=1){
      if(!rts[i].empty()) continue;
      M w=M(rt).pow((md-1)/(i<<1));
      M rw=w.inv();
      rts[i].resize(i);rrts[i].resize(i);
      rts[i][0]=M(1);rrts[i][0]=M(1);
      for(int k=1;k<i;k++){
        rts[i][k]=rts[i][k-1]*w;
        rrts[i][k]=rrts[i][k-1]*rw;
      }
    }
  }

  void ntt(vector<M> &as,bool f,int n=-1){
    if(n==-1) n=as.size();
    assert((n&(n-1))==0);
    ensure_base(n);

    for(int i=0,j=1;j+1<n;j++){
      for(int k=n>>1;k>(i^=k);k>>=1);
      if(i>j) swap(as[i],as[j]);
    }

    for(int i=1;i<n;i<<=1){
      for(int j=0;j<n;j+=i*2){
        for(int k=0;k<i;k++){
          M z=as[i+j+k]*(f?rrts[i][k]:rts[i][k]);
          as[i+j+k]=as[j+k]-z;
          as[j+k]+=z;
        }
      }
    }

    if(f){
      M tmp=M(n).inv();
      for(int i=0;i<n;i++) as[i]*=tmp;
    }
  }

  vector<M> multiply(vector<M> as,vector<M> bs){
    int need=as.size()+bs.size()-1;
    int sz=1;
    while(sz<need) sz<<=1;
    as.resize(sz,M(0));
    bs.resize(sz,M(0));

    ntt(as,0);ntt(bs,0);
    for(int i=0;i<sz;i++) as[i]*=bs[i];
    ntt(as,1);

    as.resize(need);
    return as;
  }

  vector<int> multiply(vector<int> as,vector<int> bs){
    vector<M> am(as.size()),bm(bs.size());
    for(int i=0;i<(int)am.size();i++) am[i]=M(as[i]);
    for(int i=0;i<(int)bm.size();i++) bm[i]=M(bs[i]);
    vector<M> cm=multiply(am,bm);
    vector<int> cs(cm.size());
    for(int i=0;i<(int)cs.size();i++) cs[i]=cm[i].v;
    return cs;
  }
};
template<int X> constexpr int NTT<X>::md;
template<int X> constexpr int NTT<X>::rt;


template<typename T,typename Transformer>
struct Convolution2D{
  using Matrix = vector< vector<T> >;
  const Transformer tran;
  Convolution2D(Transformer tran):tran(tran){}

  void transpose(Matrix &as){
    int n=as.size(),m=as[0].size();
    Matrix cs(as);
    as.assign(m,vector<T>(n));
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        as[j][i]=cs[i][j];
  }

  void transform(Matrix &as,bool f){
    for(int t=0;t<2;t++){
      for(auto &a:as) tran(a,f);
      transpose(as);
    }
  }

  Matrix multiply(Matrix as,Matrix bs){
    int nt=as.size()+bs.size()-1;
    int mt=as[0].size()+bs[0].size()-1;
    int n=1,m=1;
    while(n<nt) n<<=1;
    while(m<mt) m<<=1;
    as.resize(n);bs.resize(n);
    for(int i=0;i<n;i++){
      as[i].resize(m,T(0));
      bs[i].resize(m,T(0));
    }
    transform(as,0);transform(bs,0);
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        as[i][j]*=bs[i][j];
    transform(as,1);
    return as;
  }
};


template<typename R, size_t N>
struct SquareMatrix{
  typedef array<R, N> arr;
  typedef array<arr, N> mat;
  mat dat;

  SquareMatrix(){
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        dat[i][j]=R::add_identity();
  }

  bool operator==(const SquareMatrix& a) const{
    return dat==a.dat;
  }

  size_t size() const{return N;};
  arr& operator[](size_t k){return dat[k];};
  const arr& operator[](size_t k) const {return dat[k];};

  static SquareMatrix add_identity(){return SquareMatrix();}
  static SquareMatrix mul_identity(){
    SquareMatrix res;
    for(size_t i=0;i<N;i++) res[i][i]=R::mul_identity();
    return res;
  }

  SquareMatrix operator*(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        for(size_t k=0;k<N;k++)
          res[i][j]=res[i][j]+(dat[i][k]*B[k][j]);
    return res;
  }

  SquareMatrix operator+(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        res[i][j]=dat[i][j]+B[i][j];
    return res;
  }

  SquareMatrix pow(long long n) const{
    SquareMatrix a=*this,res=mul_identity();
    while(n){
      if(n&1) res=res*a;
      a=a*a;
      n>>=1;
    }
    return res;
  }
};

//INSERT ABOVE HERE

NTT<2> ntt;
using M = NTT<2>::M;
auto tran=[](auto &as,bool f){ntt.ntt(as,f);};
Convolution2D<M, decltype(tran)> conv(tran);

struct Ring{
  vector<M> dat;
  Ring(){};
  Ring(vector<M> dat):dat(dat){};
  static Ring add_identity();
  static Ring mul_identity();
  Ring operator*(const Ring &a)const{
    auto res=Ring(dat);
    for(int i=0;i<(int)dat.size();i++) res.dat[i]*=a.dat[i];
    return res;
  }
  Ring operator+(const Ring &a)const{
    auto res=Ring(dat);
    for(int i=0;i<(int)dat.size();i++) res.dat[i]+=a.dat[i];
    return res;
  }
};

Ring add_id, mul_id;
Ring Ring::add_identity(){return add_id;};
Ring Ring::mul_identity(){return mul_id;};

signed main(){
  int h,w;
  long long k;
  cin>>h>>w>>k;
  h=1<<h;
  w=1<<w;
  vector< vector<int> > tt(h,vector<int>(w));
  vector< vector<int> > gg(h,vector<int>(w));
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>tt[i][j];
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>gg[i][j];

  using Matrix = vector< vector<M> >;
  Matrix T(h,vector<M>(w));
  Matrix G(h,vector<M>(w));
  Matrix W(h,vector<M>(w));
  Matrix H(h,vector<M>(w));
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      T[i][j]=tt[i][j]>=0?tt[i][j]:0;
      G[i][j]=gg[i][j]>=0?gg[i][j]:0;
      W[i][j]=tt[i][j]>=0?1:0;
      H[i][j]=T[i][j]*G[i][j];
    }
  }

  auto flatten=
    [&](Matrix A){
      conv.transform(A,false);
      vector<M> dat(h*w);
      for(int i=0;i<h*w;i++) dat[i]=A[i/w][i%w];
      return Ring(dat);
    };

  {
    Matrix id(h,vector<M>(w,M(0)));
    add_id=flatten(id);
    id[0][0]=1;
    mul_id=flatten(id);
  }

  using SM = SquareMatrix<Ring, 4>;
  SM P;
  P[0][0]=flatten(W);
  P[1][0]=flatten(T);P[1][1]=flatten(W);
  P[2][0]=flatten(H);P[2][1]=flatten(G);P[2][2]=flatten(W);
  P[3][0]=flatten(H);P[3][1]=flatten(G);P[3][2]=flatten(W);
  P[3][3]=Ring::mul_identity();

  auto val=P.pow(k)[3][0];

  Matrix res(h,vector<M>(w));
  for(int i=0;i<h*w;i++) res[i/w][i%w]=val.dat[i];
  conv.transform(res,true);

  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(j) cout<<" ";
      cout<<res[i][j];
    }
    cout<<"\n";
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 2490
memory_kb: 80936
final_rank: 5

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


constexpr int bmds(int x){
  const int v[] = {1012924417, 924844033, 998244353,
                   897581057, 645922817};
  return v[x];
}
constexpr int brts(int x){
  const int v[] = {5, 5, 3, 3, 3};
  return v[x];
}


template<int X>
struct NTT{
  static constexpr int md = bmds(X);
  static constexpr int rt = brts(X);

  inline int add(int a,int b){
    a+=b;
    if(a>=md) a-=md;
    return a;
  }

  inline int mul(int a,int b){
    return 1LL*a*b%md;
  }

  inline int pow(int a,int b){
    int res=1;
    while(b){
      if(b&1) res=mul(res,a);
      a=mul(a,a);
      b>>=1;
    }
    return res;
  }

  inline int inv(int x){
    return pow(x,md-2);
  }
  vector<vector<int> > rts,rrts;

  void ensure_base(int n){
    if((int)rts.size()>=n) return;
    rts.resize(n);rrts.resize(n);
    for(int i=1;i<n;i<<=1){
      if(!rts[i].empty()) continue;
      int w=pow(rt,(md-1)/(i<<1));
      int rw=inv(w);
      rts[i].resize(i);rrts[i].resize(i);
      rts[i][0]=1;rrts[i][0]=1;
      for(int k=1;k<i;k++){
        rts[i][k]=mul(rts[i][k-1],w);
        rrts[i][k]=mul(rrts[i][k-1],rw);
      }
    }
  }

  template<typename A>
  void ntt(A &a,bool f,int n=-1){
    if(n==-1) n=a.size();
    assert((n&(n-1))==0);
    ensure_base(n);

    for(int i=0,j=1;j+1<n;j++){
      for(int k=n>>1;k>(i^=k);k>>=1);
      if(i>j) swap(a[i],a[j]);
    }

    for(int i=1;i<n;i<<=1){
      for(int j=0;j<n;j+=i*2){
        for(int k=0;k<i;k++){
          int z=mul(a[i+j+k],f?rrts[i][k]:rts[i][k]);
          a[i+j+k]=add(a[j+k],md-z);
          a[j+k]=add(a[j+k],z);
        }
      }
    }

    if(f){
      int tmp=inv(n);
      for(int i=0;i<n;i++) a[i]=mul(a[i],tmp);
    }
  }
};

int h,w;
const int MAX = 1<<9;
using Matrix = array< array<int, MAX>, MAX >;

template<typename T,typename Transformer>
struct Convolution2D{
  const Transformer tran;
  Convolution2D(Transformer tran):tran(tran){}

  void transpose(Matrix &as){
    Matrix cs(as);
    for(int i=0;i<MAX;i++)
      for(int j=0;j<MAX;j++)
        as[j][i]=cs[i][j];
    swap(h,w);
  }

  void transform(Matrix &as,bool f){
    for(int t=0;t<2;t++){
      for(auto &a:as) tran(a,f,w);
      transpose(as);
    }
  }
};


struct FastIO{
  FastIO(){
    cin.tie(0);
    ios::sync_with_stdio(0);
  }
}fastio_beet;


template<size_t N,typename R>
struct SquareMatrix{
  typedef array<R, N> arr;
  typedef array<arr, N> mat;
  mat dat;

  SquareMatrix(){
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        dat[i][j]=R::add_identity();
  }

  bool operator==(const SquareMatrix& a) const{
    return dat==a.dat;
  }

  size_t size() const{return N;};
  arr& operator[](size_t k){return dat[k];};
  const arr& operator[](size_t k) const {return dat[k];};

  static SquareMatrix add_identity(){return SquareMatrix();}
  static SquareMatrix mul_identity(){
    SquareMatrix res;
    for(size_t i=0;i<N;i++) res[i][i]=R::mul_identity();
    return res;
  }

  SquareMatrix operator*(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        for(size_t k=0;k<N;k++)
          res[i][j]=res[i][j]+(dat[i][k]*B[k][j]);
    return res;
  }

  SquareMatrix operator+(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        res[i][j]=dat[i][j]+B[i][j];
    return res;
  }

  SquareMatrix pow(long long n) const{
    SquareMatrix a=*this,res=mul_identity();
    while(n){
      if(n&1) res=res*a;
      a=a*a;
      n>>=1;
    }
    return res;
  }
};

//INSERT ABOVE HERE
using ll = long long;
NTT<2> ntt;
auto tran=[](auto &as,bool f,int n){ntt.ntt(as,f,n);};
Convolution2D<int, decltype(tran)> conv(tran);
auto mul=[](int a,int b){return (ll)a*b%ntt.md;};

struct Ring{
  vector<int> dat;
  Ring():dat(MAX*MAX,0){};
  Ring(vector<int>  dat):dat(dat){};
  static Ring add_identity();
  static Ring mul_identity();
  Ring operator*(const Ring &a)const{
    auto res=Ring();
    for(int i=0;i<h*w;i++)
      res.dat[i]=(ll)dat[i]*a.dat[i]%ntt.md;
    return res;
  }
  Ring operator+(const Ring &a)const{
    auto res=Ring();
    for(int i=0;i<h*w;i++)
      res.dat[i]=((ll)dat[i]+a.dat[i])%ntt.md;
    return res;
  }
};
Ring add_id, mul_id;
Ring Ring::add_identity(){return add_id;};
Ring Ring::mul_identity(){return mul_id;};

signed main(){
  long long k;
  cin>>h>>w>>k;
  h=1<<h;
  w=1<<w;
  vector< vector<int> > tt(h,vector<int>(w));
  vector< vector<int> > gg(h,vector<int>(w));
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>tt[i][j];
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>gg[i][j];


  Matrix T,G,W,H;
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      T[i][j]=tt[i][j]>=0?tt[i][j]:0;
      G[i][j]=gg[i][j]>=0?gg[i][j]:0;
      W[i][j]=tt[i][j]>=0?1:0;
      H[i][j]=mul(T[i][j],G[i][j]);
    }
  }

  auto flatten=
    [&](Matrix A){
      conv.transform(A,false);
      Ring res;
      for(int i=0;i<h*w;i++) res.dat[i]=A[i/w][i%w];
      return res;
    };

  {
    Matrix id;
    for(int i=0;i<MAX;i++)
      for(int j=0;j<MAX;j++)
        id[i][j]=0;
    add_id=flatten(id);
    id[0][0]=1;
    mul_id=flatten(id);
  }

  using SM = SquareMatrix<4, Ring>;
  SM P;
  P[0][0]=flatten(W);
  P[1][0]=flatten(T);P[1][1]=flatten(W);
  P[2][0]=flatten(H);P[2][1]=flatten(G);P[2][2]=flatten(W);
  P[3][0]=flatten(H);P[3][1]=flatten(G);P[3][2]=flatten(W);
  P[3][3]=Ring::mul_identity();

  auto val=P.pow(k)[3][0];
  Matrix res;
  for(int i=0;i<h*w;i++) res[i/w][i%w]=val.dat[i];
  conv.transform(res,true);

  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(j) cout<<" ";
      cout<<res[i][j];
    }
    cout<<"\n";
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 1860
memory_kb: 81944
final_rank: 4

code_snippet: #include<bits/stdc++.h>
using namespace std;
using Int = long long;
template<typename T1,typename T2> inline void chmin(T1 &a,T2 b){if(a>b) a=b;}
template<typename T1,typename T2> inline void chmax(T1 &a,T2 b){if(a<b) a=b;}


constexpr int bmds(int x){
  const int v[] = {1012924417, 924844033, 998244353,
                   897581057, 645922817};
  return v[x];
}
constexpr int brts(int x){
  const int v[] = {5, 5, 3, 3, 3};
  return v[x];
}


template<int X>
struct NTT{
  static constexpr int md = bmds(X);
  static constexpr int rt = brts(X);

  inline int add(int a,int b){
    a+=b;
    if(a>=md) a-=md;
    return a;
  }

  inline int mul(int a,int b){
    return 1LL*a*b%md;
  }

  inline int pow(int a,int b){
    int res=1;
    while(b){
      if(b&1) res=mul(res,a);
      a=mul(a,a);
      b>>=1;
    }
    return res;
  }

  inline int inv(int x){
    return pow(x,md-2);
  }

  // assume md % 4 = 1
  // if md % 4 == 3, then x = a^{(md+1)/4}
  inline int sqrt(int a){
    if(a==0) return 0;
    if(pow(a,(md-1)/2)!=1) return -1;
    int q=md-1,m=0;
    while(~q&1) q>>=1,m++;
    mt19937 mt;
    int z=mt()%md;
    while(pow(z,(md-1)/2)!=md-1) z=mt()%md;
    int c=pow(z,q),t=pow(a,q),r=pow(a,(q+1)/2);
    while(m>1){
      if(pow(t,1<<(m-2))!=1)
        r=mul(r,c),t=mul(t,mul(c,c));
      c=mul(c,c);
      m--;
    }
    return r;
  }

  vector<vector<int> > rts,rrts;

  void ensure_base(int n){
    if((int)rts.size()>=n) return;
    rts.resize(n);rrts.resize(n);
    for(int i=1;i<n;i<<=1){
      if(!rts[i].empty()) continue;
      int w=pow(rt,(md-1)/(i<<1));
      int rw=inv(w);
      rts[i].resize(i);rrts[i].resize(i);
      rts[i][0]=1;rrts[i][0]=1;
      for(int k=1;k<i;k++){
        rts[i][k]=mul(rts[i][k-1],w);
        rrts[i][k]=mul(rrts[i][k-1],rw);
      }
    }
  }

  void ntt(vector<int> &a,bool f,int n=-1){
    if(n==-1) n=a.size();
    assert((n&(n-1))==0);
    ensure_base(n);

    for(int i=0,j=1;j+1<n;j++){
      for(int k=n>>1;k>(i^=k);k>>=1);
      if(i>j) swap(a[i],a[j]);
    }

    for(int i=1;i<n;i<<=1){
      for(int j=0;j<n;j+=i*2){
        for(int k=0;k<i;k++){
          int z=mul(a[i+j+k],f?rrts[i][k]:rts[i][k]);
          a[i+j+k]=add(a[j+k],md-z);
          a[j+k]=add(a[j+k],z);
        }
      }
    }

    if(f){
      int tmp=inv(n);
      for(int i=0;i<n;i++) a[i]=mul(a[i],tmp);
    }
  }
};


template<typename T,typename Transformer>
struct Convolution2D{
  using Matrix = vector< vector<T> >;
  const Transformer tran;
  Convolution2D(Transformer tran):tran(tran){}

  void transpose(Matrix &as){
    int n=as.size(),m=as[0].size();
    Matrix cs(as);
    as.assign(m,vector<T>(n));
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        as[j][i]=cs[i][j];
  }

  void transform(Matrix &as,bool f){
    for(int t=0;t<2;t++){
      for(auto &a:as) tran(a,f);
      transpose(as);
    }
  }

  template<typename Mul>
  Matrix multiply(Matrix as,Matrix bs,Mul mul){
    int nt=as.size()+bs.size()-1;
    int mt=as[0].size()+bs[0].size()-1;
    int n=1,m=1;
    while(n<nt) n<<=1;
    while(m<mt) m<<=1;
    as.resize(n);bs.resize(n);
    for(int i=0;i<n;i++){
      as[i].resize(m,T());
      bs[i].resize(m,T());
    }
    transform(as,0);transform(bs,0);
    for(int i=0;i<n;i++)
      for(int j=0;j<m;j++)
        as[i][j]=mul(as[i][j],bs[i][j]);
    transform(as,1);
    return as;
  }
};


struct FastIO{
  FastIO(){
    cin.tie(0);
    ios::sync_with_stdio(0);
  }
}fastio_beet;


template<size_t N,typename R>
struct SquareMatrix{
  typedef array<R, N> arr;
  typedef array<arr, N> mat;
  mat dat;

  SquareMatrix(){
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        dat[i][j]=R::add_identity();
  }

  bool operator==(const SquareMatrix& a) const{
    return dat==a.dat;
  }

  size_t size() const{return N;};
  arr& operator[](size_t k){return dat[k];};
  const arr& operator[](size_t k) const {return dat[k];};

  static SquareMatrix add_identity(){return SquareMatrix();}
  static SquareMatrix mul_identity(){
    SquareMatrix res;
    for(size_t i=0;i<N;i++) res[i][i]=R::mul_identity();
    return res;
  }

  SquareMatrix operator*(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        for(size_t k=0;k<N;k++)
          res[i][j]=res[i][j]+(dat[i][k]*B[k][j]);
    return res;
  }

  SquareMatrix operator+(const SquareMatrix &B) const{
    SquareMatrix res;
    for(size_t i=0;i<N;i++)
      for(size_t j=0;j<N;j++)
        res[i][j]=dat[i][j]+B[i][j];
    return res;
  }

  SquareMatrix pow(long long n) const{
    SquareMatrix a=*this,res=mul_identity();
    while(n){
      if(n&1) res=res*a;
      a=a*a;
      n>>=1;
    }
    return res;
  }
};

//INSERT ABOVE HERE
using ll = long long;
NTT<2> ntt;
auto tran=[](auto &as,bool f){ntt.ntt(as,f);};
Convolution2D<int, decltype(tran)> conv(tran);
auto mul=[](int a,int b){return (ll)a*b%ntt.md;};

int h,w;
long long k;

signed main(){
  cin>>h>>w>>k;
  h=1<<h;
  w=1<<w;
  vector< vector<int> > tt(h,vector<int>(w));
  vector< vector<int> > gg(h,vector<int>(w));
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>tt[i][j];
  for(int i=0;i<h;i++)
    for(int j=0;j<w;j++)
      cin>>gg[i][j];

  struct Ring{
    vector< vector<int> > dat;
    Ring(){dat.assign(h,vector<int>(w,0));};
    Ring(vector< vector<int> > dat):dat(dat){};
    static Ring add_identity(){
      auto res=Ring();
      conv.transform(res.dat,false);
      return res;
    };
    static Ring mul_identity(){
      auto res=Ring();
      res.dat[0][0]=1;
      conv.transform(res.dat,false);
      return res;
    };
    Ring operator*(const Ring &a)const{
      auto res=Ring();
      for(int i=0;i<h;i++)
        for(int j=0;j<w;j++)
          res.dat[i][j]=(ll)dat[i][j]*a.dat[i][j]%ntt.md;
      return res;
    }
    Ring operator+(const Ring &a)const{
      auto res=Ring();
      for(int i=0;i<h;i++)
        for(int j=0;j<w;j++)
          res.dat[i][j]=((ll)dat[i][j]+a.dat[i][j])%ntt.md;
      return res;
    }
  };

  Ring T,G,W,H;
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      T.dat[i][j]=tt[i][j]>=0?tt[i][j]:0;
      G.dat[i][j]=gg[i][j]>=0?gg[i][j]:0;
      W.dat[i][j]=tt[i][j]>=0?1:0;
      H.dat[i][j]=mul(T.dat[i][j],G.dat[i][j]);
    }
  }

  using SM = SquareMatrix<4, Ring>;
  SM P;
  P[0][0]=W;
  P[1][0]=T;P[1][1]=W;
  P[2][0]=H;P[2][1]=G;P[2][2]=W;
  P[3][0]=H;P[3][1]=G;P[3][2]=W;P[3][3]=Ring::mul_identity();

  for(int i=0;i<4;i++)
    for(int j=0;j<4;j++)
      if(i!=3||j!=3)
        conv.transform(P[i][j].dat,false);

  auto res=P.pow(k)[3][0];
  conv.transform(res.dat,true);

  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(j) cout<<" ";
      cout<<res.dat[i][j];
    }
    cout<<"\n";
  }
  cout<<flush;
  return 0;
}
accuracy: 1
time_ms: 6660
memory_kb: 78060
final_rank: 6

code_snippet: #include <bits/stdc++.h>
using namespace std;
using lint = long long;
template<class T = int> using V = vector<T>;
template<class T = int> using VV = V< V<T> >;

template<unsigned P> struct ModInt {
  using M = ModInt;
  unsigned v;
  constexpr ModInt() : v(0) {}
  constexpr ModInt(auto x) : v(x >= 0 ? x % P : (P - -x % P) % P) {}
  constexpr ModInt(unsigned v, int) : v(v) {}
  static constexpr unsigned p() { return P; }
  M operator+() const { return *this; }
  M operator-() const { return {v ? P - v : 0, 0}; }
  explicit operator bool() const noexcept { return v; }
  bool operator!() const noexcept { return !(bool)*this; }
  M operator*(M r) const { return M(*this) *= r; }
  M operator/(M r) const { return M(*this) /= r; }
  M operator+(M r) const { return M(*this) += r; }
  M operator-(M r) const { return M(*this) -= r; }
  bool operator==(M r) const { return v == r.v; }
  bool operator!=(M r) const { return !(*this == r); }
  M& operator*=(M r) { v = (uint64_t)v * r.v % P; return *this; }
  M& operator/=(M r) { return *this *= r.inv(); }
  M& operator+=(M r) { if ((v += r.v) >= P) v -= P; return *this; }
  M& operator-=(M r) { if ((v += P - r.v) >= P) v -= P; return *this; }
  M inv() const {
    int a = v, b = P, x = 1, u = 0;
    while (b) {
      int q = a / b;
      swap(a -= q * b, b);
      swap(x -= q * u, u);
    }
    assert(a == 1);
    return x;
  }
  M pow(auto n) const {
    if (n < 0) return pow(-n).inv();
    M res = 1;
    for (M a = *this; n; a *= a, n >>= 1) if (n & 1) res *= a;
    return res;
  }
  friend M operator*(auto l, M r) { return M(l) *= r; }
  friend M operator/(auto l, M r) { return M(l) /= r; }
  friend M operator+(auto l, M r) { return M(l) += r; }
  friend M operator-(auto l, M r) { return M(l) -= r; }
  friend ostream& operator<<(ostream& os, M r) { return os << r.v; }
  friend istream& operator>>(istream& is, M& r) { lint x; is >> x; r = x; return is; }
  friend bool operator==(auto l, M r) { return M(l) == r; }
  friend bool operator!=(auto l, M r) { return !(l == r); }
};
using Mint = ModInt<998244353>;

template<unsigned P, unsigned g = 6420> void ntt(V< ModInt<P> >& a, bool inv = false) {
  int n = a.size();
  assert(__builtin_popcount(n) == 1);
  int j = 0;
  for (int i = 1; i < n; ++i) {
    int w = n >> 1;
    while (j >= w) j -= w, w >>= 1;
    j += w;
    if (i < j) swap(a[i], a[j]);
  }
  assert((P - 1) % n == 0);
  auto xi = ModInt<P>(g).pow((P - 1) / n);
  if (inv) xi = xi.inv();
  for (int k = 0; 1 << k < n; ++k) {
    const int w = 1 << k;
    const auto dt = xi.pow(n >> k + 1);
    for (int s = 0; s < n; s += 2 * w) {
      ModInt<P> t = 1;
      for (int i = s; i < s + w; ++i) {
        auto p = a[i], q = a[i + w] * t;
        a[i] = p + q, a[i + w] = p - q;
        t *= dt;
      }
    }
  }
}
template<unsigned P, unsigned g = 6420> V< ModInt<P> > multiply(const V< ModInt<P> >& a, const V< ModInt<P> >& b) {
  if (a.empty() or b.empty()) return {};
  int sz = a.size() + b.size() - 1, n = 1 << __lg(2 * sz - 1);
  auto _a = a, _b = b;
  _a.resize(n), _b.resize(n);
  ntt<P, g>(_a), ntt<P, g>(_b);
  for (int i = 0; i < n; ++i) _a[i] *= _b[i];
  ntt<P, g>(_a, true);
  _a.resize(sz);
  const auto inv_n = ModInt<P>(n).inv();
  for (auto&& e : _a) e *= inv_n;
  return _a;
}

template<class T> V<T> operator*(const VV<T>& A, const V<T>& x) {
  assert(A[0].size() == x.size());
  V<T> res(A.size());
  for (int i = 0; i < (int) A.size(); ++i) {
    res[i] = inner_product(begin(A[i]), end(A[i]), begin(x), (T) 0);
  }
  return res;
}
template<class T> VV<T> operator*(const VV<T>& A, const VV<T>& B) {
  assert(A[0].size() == B.size());
  VV<T> res(A.size(), V<T>(B[0].size()));
  for (int i = 0; i < (int) A.size(); ++i) for (int k = 0; k < (int) A[0].size(); ++k) for (int j = 0; j < (int) B[0].size(); ++j) {
    res[i][j] += A[i][k] * B[k][j];
  }
  return res;
}
template<class T> VV<T>& operator*=(VV<T>& A, const VV<T>& B) { return A = A * B; }
template<class T> VV<T> I(int n) {
  VV<T> res(n, V<T>(n));
  for (int i = 0; i < n; ++i) res[i][i] = 1;
  return res;
}
template<class T> VV<T> pow(VV<T> A, lint n) {
  auto res = I<T>(A.size());
  while (n) {
    if (n & 1) res *= A;
    A *= A;
    n >>= 1;
  }
  return res;
}

int main() {
  cin.tie(nullptr); ios::sync_with_stdio(false);
  int h, w, k; cin >> h >> w >> k;
  h = 1 << h, w = 1 << w;
  VV<Mint> c(h, V<Mint>(w));
  VV<Mint> t(h, V<Mint>(w));
  for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) {
    int T; cin >> T;
    c[i][j] = (int)(T != -1);
    t[i][j] = T == -1 ? 0 : T;
  }
  VV<Mint> g(h, V<Mint>(w));
  VV<Mint> tg(h, V<Mint>(w));
  for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) {
    int G; cin >> G;
    g[i][j] = G == -1 ? 0 : G;
    tg[i][j] = t[i][j] * g[i][j];
  }

  auto ntt2D = [&](VV<Mint>& v, bool inv = false) -> void {
    for (auto&& e : v) {
      ntt(e, inv);
    }
    for (int j = 0; j < w; ++j) {
      V<Mint> a(h);
      for (int i = 0; i < h; ++i) {
        a[i] = v[i][j];
      }
      ntt(a, inv);
      for (int i = 0; i < h; ++i) {
        v[i][j] = a[i];
      }
    }
    if (inv) {
      for (auto&& e : v) for (auto&& f : e) {
        f /= h * w;
      }
    }
  };

  ntt2D(c);
  ntt2D(t);
  ntt2D(tg);
  ntt2D(g);

  VV<Mint> res(h, V<Mint>(w));
  for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) {
    V<Mint> dp(5);
    dp[0] = 1;
    VV<Mint> A(5, V<Mint>(5));
    A[0][0] = A[1][1] = A[2][2] = A[3][3] = c[i][j];
    A[1][0] = t[i][j];
    A[2][0] = tg[i][j], A[2][1] = g[i][j];
    A[3][0] = g[i][j];
    A[4][2] = A[4][4] = 1;
    dp = pow(A, k + 1) * dp;
    res[i][j] = dp[4];
  }

  ntt2D(res, true);
  for (int i = 0; i < h; ++i) for (int j = 0; j < w; ++j) {
    cout << res[i][j] << " \n"[j == w - 1];
  }
}
accuracy: 1
time_ms: 3200
memory_kb: 8132
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
//const ll MOD=1000000007;
const ll MOD=998244353;

#define endl "\n"

  
template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,const pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,const vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}


  

template< int mod, int primitiveroot >
struct NumberTheoreticTransform {
  vector< vector< int > > rts, rrts;
  void ensure_base(int N) {
    if(rts.size() >= N) return;
    rts.resize(N), rrts.resize(N);
    for(int i = 1; i < N; i <<= 1) {
      if(rts[i].size()) continue;
      int w = mod_pow(primitiveroot, (mod - 1) / (i * 2));
      int rw = inverse(w);
      rts[i].resize(i), rrts[i].resize(i);
      rts[i][0] = 1, rrts[i][0] = 1;
      for(int k = 1; k < i; k++) {
        rts[i][k] = mul(rts[i][k - 1], w);
        rrts[i][k] = mul(rrts[i][k - 1], rw);
      }
    }
  }

  inline int mod_pow(int x, int n) {
    int ret = 1;
    while(n > 0) {
      if(n & 1) ret = mul(ret, x);
      x = mul(x, x);
      n >>= 1;
    }
    return ret;
  }

  inline int inverse(int x) {
    return mod_pow(x, mod - 2);
  }

  inline int add(int x, int y) {
    x += y;
    if(x >= mod) x -= mod;
    return x;
  }

  inline int mul(int a, int b) {
    return int(1LL * a * b % mod);
  }

  void DiscreteFourierTransform(vector< int > &F, bool rev) {
    const int N = (int) F.size();
    //ensure_base(N);
    for(int i = 0, j = 1; j + 1 < N; j++) {
      for(int k = N >> 1; k > (i ^= k); k >>= 1);
      if(i > j) swap(F[i], F[j]);
    }
    for(int i = 1; i < N; i <<= 1) {
      for(int j = 0; j < N; j += i * 2) {
        for(int k = 0; k < i; k++) {
          int s = F[j + k], t = mul(F[j + k + i], rev ? rrts[i][k] : rts[i][k]);
          F[j + k] = add(s, t), F[j + k + i] = add(s, mod - t);
        }
      }
    }
    if(rev) {
      int temp = inverse(N);
      for(int i = 0; i < N; i++) F[i] = mul(F[i], temp);
    }
  }

  vector< int > Multiply(const vector< int > &A, const vector< int > &B) {
    int sz = 1;
    while(sz < A.size() + B.size() - 1) sz <<= 1;
    vector< int > F(sz), G(sz);
    for(int i = 0; i < A.size(); i++) F[i] = A[i];
    for(int i = 0; i < B.size(); i++) G[i] = B[i];
    DiscreteFourierTransform(F, false);
    DiscreteFourierTransform(G, false);
    for(int i = 0; i < sz; i++) F[i] = mul(F[i], G[i]);
    DiscreteFourierTransform(F, true);
    F.resize(A.size() + B.size() - 1);
    return F;
  }
};


const int mod=MOD;

inline int mul(int a, int b) {
  return int(1LL * a * b % mod);
}

inline int mod_pow(int x, int n) {
  int ret = 1;
  while(n > 0) {
    if(n & 1) ret = mul(ret, x);
    x = mul(x, x);
    n >>= 1;
  }
  return ret;
}

inline int inverse(int x) {
  return mod_pow(x, mod - 2);
}

inline int add(int x, int y) {
  x += y;
  if(x >= mod) x -= mod;
  return x;
}







const int lg=7;
const int SIZE=1<<lg;
NumberTheoreticTransform<MOD,3> NTT;
const int ms=4;

int ans[ms][ms][SIZE][SIZE];
int A[ms][ms][SIZE][SIZE];
int bk[ms][ms];
vector<int> func(SIZE,0);







void prod(){
  for(int i=0;i<SIZE;i++){
    for(int j=0;j<SIZE;j++){
      for(int k=0;k<ms;k++){
        for(int l=0;l<ms;l++){
          int sum=0;
          for(int m=0;m<ms;m++){
            int p=mul(ans[k][m][i][j],A[m][l][i][j]);
            sum=add(sum,p);
          }
          bk[k][l]=sum;
        }
      }
      for(int k=0;k<ms;k++){
        for(int l=0;l<ms;l++){
          ans[k][l][i][j]=bk[k][l];
        }
      }
    }
  }
}

void dbl(){
  for(int i=0;i<SIZE;i++){
    for(int j=0;j<SIZE;j++){
      for(int k=0;k<ms;k++){
        for(int l=0;l<ms;l++){
          int sum=0;
          for(int m=0;m<ms;m++){
            int p=mul(A[k][m][i][j],A[m][l][i][j]);
            sum=add(sum,p);
          }
          bk[k][l]=sum;
        }
      }
      for(int k=0;k<ms;k++){
        for(int l=0;l<ms;l++){
          A[k][l][i][j]=bk[k][l];
        }
      }
    }
  }
}

void init(){
  NTT.ensure_base(SIZE);
}

void FFT_A(bool rev){
  for(int k=0;k<ms;k++){
    for(int l=0;l<ms;l++){
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          func[j]=A[k][l][i][j];
        }
        NTT.DiscreteFourierTransform(func,rev);
        for(int j=0;j<SIZE;j++){
          A[k][l][i][j]=func[j];
        }
      }
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          func[j]=A[k][l][j][i];
        }
        NTT.DiscreteFourierTransform(func,rev);
        for(int j=0;j<SIZE;j++){
          A[k][l][j][i]=func[j];
        }
      }
    }
  }
}

void FFT_ans(bool rev){
  for(int k=0;k<ms;k++){
    for(int l=0;l<ms;l++){
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          func[j]=ans[k][l][i][j];
        }
        NTT.DiscreteFourierTransform(func,rev);
        for(int j=0;j<SIZE;j++){
          ans[k][l][i][j]=func[j];
        }
      }
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          func[j]=ans[k][l][j][i];
        }
        NTT.DiscreteFourierTransform(func,rev);
        for(int j=0;j<SIZE;j++){
          ans[k][l][j][i]=func[j];
        }
      }
    }
  }
}

int h,w;

void con_A(){
  for(int k=0;k<ms;k++){
    for(int l=0;l<ms;l++){
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          if(i>=h || j>=w){A[k][l][i%h][j%w]=add(A[k][l][i%h][j%w],A[k][l][i][j]); A[k][l][i][j]=0;}
        }
      }
    }
  }
}

void con_ans(){
  for(int k=0;k<ms;k++){
    for(int l=0;l<ms;l++){
      for(int i=0;i<SIZE;i++){
        for(int j=0;j<SIZE;j++){
          if(i>=h || j>=w){ans[k][l][i%h][j%w]=add(ans[k][l][i%h][j%w],ans[k][l][i][j]); ans[k][l][i][j]=0;}
        }
      }
    }
  }
}

void A_A(){
  FFT_A(false);
  dbl();
  FFT_A(true);
  con_A();
}

void ans_A(){
  FFT_A(false);
  FFT_ans(false);
  prod();
  FFT_A(true);
  FFT_ans(true);
  con_ans();
}

void cul(ll k){
  while(k>0){
    if(k&1){ans_A();}
    A_A();
    k>>=1;
  }
}



int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  init();
  for(int i=0;i<ms;i++){ans[i][i][0][0]=1;}
  ll k;
  cin>>h>>w>>k;
  assert(h<lg && w<lg);
  h=1<<h;
  w=1<<w;
  k++;
  A[0][0][0][0]=1;
  A[0][2][0][0]=1;
  vector<vector<int>> T(h,vector<int>(w));
  vector<vector<int>> G(h,vector<int>(w));
  cin>>T>>G;
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      if(T[i][j]==-1){continue;}
      for(int k=1;k<ms;k++){A[k][k][i][j]=add(A[k][k][i][j],1);}
      A[2][1][i][j]=add(A[2][1][i][j],mul(T[i][j],G[i][j]));
      A[2][3][i][j]=add(A[2][3][i][j],G[i][j]);
      A[3][1][i][j]=add(A[3][1][i][j],T[i][j]);
    }
  }
  cul(k);
  for(int i=0;i<h;i++){
    for(int j=0;j<w;j++){
      cout<<ans[0][1][i][j];
      if(j+1!=w){cout<<" ";}
    }
    cout<<endl;
  }

  return 0;
}
accuracy: 0.11428571428571428
time_ms: 570
memory_kb: 5272
final_rank: 7

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
//const ll MOD=1000000007;
const ll MOD=998244353;

#define endl "\n"

  
template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,const pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,const vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}


template< int mod, int primitiveroot >
struct NumberTheoreticTransform {
  vector< vector< int > > rts, rrts;
  void ensure_base(int N) {
    if(rts.size() >= N) return;
    rts.resize(N), rrts.resize(N);
    for(int i = 1; i < N; i <<= 1) {
      if(rts[i].size()) continue;
      int w = mod_pow(primitiveroot, (mod - 1) / (i * 2));
      int rw = inverse(w);
      rts[i].resize(i), rrts[i].resize(i);
      rts[i][0] = 1, rrts[i][0] = 1;
      for(int k = 1; k < i; k++) {
        rts[i][k] = mul(rts[i][k - 1], w);
        rrts[i][k] = mul(rrts[i][k - 1], rw);
      }
    }
  }

  inline int mod_pow(int x, int n) {
    int ret = 1;
    while(n > 0) {
      if(n & 1) ret = mul(ret, x);
      x = mul(x, x);
      n >>= 1;
    }
    return ret;
  }

  inline int inverse(int x) {
    return mod_pow(x, mod - 2);
  }

  inline int add(int x, int y) {
    x += y;
    if(x >= mod) x -= mod;
    return x;
  }

  inline int mul(int a, int b) {
    return int(1LL * a * b % mod);
  }

  void DiscreteFourierTransform(vector< int > &F, bool rev) {
    const int N = (int) F.size();
    //ensure_base(N);
    for(int i = 0, j = 1; j + 1 < N; j++) {
      for(int k = N >> 1; k > (i ^= k); k >>= 1);
      if(i > j) swap(F[i], F[j]);
    }
    for(int i = 1; i < N; i <<= 1) {
      for(int j = 0; j < N; j += i * 2) {
        for(int k = 0; k < i; k++) {
          int s = F[j + k], t = mul(F[j + k + i], rev ? rrts[i][k] : rts[i][k]);
          F[j + k] = add(s, t), F[j + k + i] = add(s, mod - t);
        }
      }
    }
    if(rev) {
      int temp = inverse(N);
      for(int i = 0; i < N; i++) F[i] = mul(F[i], temp);
    }
  }

  vector< int > Multiply(const vector< int > &A, const vector< int > &B) {
    int sz = 1;
    while(sz < A.size() + B.size() - 1) sz <<= 1;
    vector< int > F(sz), G(sz);
    for(int i = 0; i < A.size(); i++) F[i] = A[i];
    for(int i = 0; i < B.size(); i++) G[i] = B[i];
    DiscreteFourierTransform(F, false);
    DiscreteFourierTransform(G, false);
    for(int i = 0; i < sz; i++) F[i] = mul(F[i], G[i]);
    DiscreteFourierTransform(F, true);
    F.resize(A.size() + B.size() - 1);
    return F;
  }
};


const int mod=MOD;

inline int mul(int a, int b) {
  return int(1LL * a * b % mod);
}

inline int mod_pow(int x, int n) {
  int ret = 1;
  while(n > 0) {
    if(n & 1) ret = mul(ret, x);
    x = mul(x, x);
    n >>= 1;
  }
  return ret;
}

inline int inverse(int x) {
  return mod_pow(x, mod - 2);
}

inline int add(int x, int y) {
  x += y;
  if(x >= mod) x -= mod;
  return x;
}




int H,W;
const int lg=9;
const int MAX_SIZE=1<<lg;
NumberTheoreticTransform<MOD,3> NTT;
const int ms=4;

vector<vector<vector<vector<int>>>> A(MAX_SIZE,vector<vector<vector<int>>>(MAX_SIZE,vector<vector<int>>(ms,vector<int>(ms))));
int mt[ms][ms];
int bk[ms][ms];
int ans[ms][ms];
vector<int> funcH,funcW;


void FFT_A(bool rev){
  for(int i=0;i<ms;i++){
    for(int j=0;j<ms;j++){
      for(int x=0;x<H;x++){
        for(int y=0;y<W;y++){
          funcW[y]=A[x][y][i][j];
        }
        NTT.DiscreteFourierTransform(funcW,rev);
        for(int y=0;y<W;y++){
          A[x][y][i][j]=funcW[y];
        }
      }
      for(int y=0;y<W;y++){
        for(int x=0;x<H;x++){
          funcH[x]=A[x][y][i][j];
        }
        NTT.DiscreteFourierTransform(funcH,rev);
        for(int x=0;x<H;x++){
          A[x][y][i][j]=funcH[x];
        }
      }
    }
  }
}

void cul(ll K){
  ll k;
  for(int x=0;x<H;x++){
    for(int y=0;y<W;y++){
      for(int i=0;i<ms;i++){
        for(int j=0;j<ms;j++){
          ans[i][j]=(i==j?1:0);
          mt[i][j]=A[x][y][i][j];
        }
      }
      k=K;
      while(k>0){
        if(k&1){
          for(int i=0;i<ms;i++){
            for(int j=0;j<ms;j++){
              bk[i][j]=0;
              for(int k=0;k<ms;k++){
                bk[i][j]=add(bk[i][j],mul(ans[i][k],mt[k][j]));
              }
            }
          }
          for(int i=0;i<ms;i++){
            for(int j=0;j<ms;j++){
              ans[i][j]=bk[i][j];
            }
          }
        }
        k>>=1;
        for(int i=0;i<ms;i++){
          for(int j=0;j<ms;j++){
            bk[i][j]=0;
            for(int k=0;k<ms;k++){
              bk[i][j]=add(bk[i][j],mul(mt[i][k],mt[k][j]));
            }
          }
        }
        for(int i=0;i<ms;i++){
          for(int j=0;j<ms;j++){
            mt[i][j]=bk[i][j];
          }
        }
      }
      for(int i=0;i<ms;i++){
        for(int j=0;j<ms;j++){
          A[x][y][i][j]=ans[i][j];
        }
      }
    }
  }
}


void init(){
  NTT.ensure_base(MAX_SIZE);
}



int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  init();
  ll k;
  cin>>H>>W>>k;
  H=1<<H;
  W=1<<W;
  funcH.resize(H);
  funcW.resize(W);
  k++;
  A[0][0][0][0]=1;
  A[0][0][0][2]=1;
  vector<vector<int>> T(H,vector<int>(W));
  vector<vector<int>> G(H,vector<int>(W));
  cin>>T>>G;
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(T[i][j]==-1){continue;}
      for(int k=1;k<ms;k++){A[i][j][k][k]=add(A[i][j][k][k],1);}
      A[i][j][2][1]=add(A[i][j][2][1],mul(T[i][j],G[i][j]));
      A[i][j][2][3]=add(A[i][j][2][3],G[i][j]);
      A[i][j][3][1]=add(A[i][j][3][1],T[i][j]);
    }
  }
  FFT_A(false);
  cul(k);
  FFT_A(true);
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      cout<<A[i][j][0][1];
      if(j+1!=W){cout<<" ";}
    }
    cout<<endl;
  }

  return 0;
}
accuracy: 1
time_ms: 1860
memory_kb: 72820
final_rank: 3

code_snippet: #include<bits/stdc++.h>
using namespace std;
typedef unsigned long long int ull;
typedef long long int ll;
typedef pair<ll,ll> pll;
typedef long double D;
typedef complex<D> P;
#define F first
#define S second
const ll E=1e18+7;
//const ll MOD=1000000007;
const ll MOD=998244353;

#define endl "\n"

  
template<typename T,typename U>istream & operator >> (istream &i,pair<T,U> &A){i>>A.F>>A.S; return i;}
template<typename T>istream & operator >> (istream &i,vector<T> &A){for(auto &I:A){i>>I;} return i;}
template<typename T,typename U>ostream & operator << (ostream &o,const pair<T,U> &A){o<<A.F<<" "<<A.S; return o;}
template<typename T>ostream & operator << (ostream &o,const vector<T> &A){ll i=A.size(); for(auto &I:A){o<<I<<(--i?" ":"");} return o;}
template<typename T>vector<T> & cset(vector<T> &A,T e=T()){for(auto &I:A){I=e;} return A;}


template< int mod, int primitiveroot >
struct NumberTheoreticTransform {
  vector< vector< int > > rts, rrts;
  void ensure_base(int N) {
    if(rts.size() >= N) return;
    rts.resize(N), rrts.resize(N);
    for(int i = 1; i < N; i <<= 1) {
      if(rts[i].size()) continue;
      int w = mod_pow(primitiveroot, (mod - 1) / (i * 2));
      int rw = inverse(w);
      rts[i].resize(i), rrts[i].resize(i);
      rts[i][0] = 1, rrts[i][0] = 1;
      for(int k = 1; k < i; k++) {
        rts[i][k] = mul(rts[i][k - 1], w);
        rrts[i][k] = mul(rrts[i][k - 1], rw);
      }
    }
  }

  inline int mod_pow(int x, int n) {
    int ret = 1;
    while(n > 0) {
      if(n & 1) ret = mul(ret, x);
      x = mul(x, x);
      n >>= 1;
    }
    return ret;
  }

  inline int inverse(int x) {
    return mod_pow(x, mod - 2);
  }

  inline int add(int x, int y) {
    x += y;
    if(x >= mod) x -= mod;
    return x;
  }

  inline int mul(int a, int b) {
    return int(1LL * a * b % mod);
  }

  void DiscreteFourierTransform(vector< int > &F, bool rev) {
    const int N = (int) F.size();
    //ensure_base(N);
    for(int i = 0, j = 1; j + 1 < N; j++) {
      for(int k = N >> 1; k > (i ^= k); k >>= 1);
      if(i > j) swap(F[i], F[j]);
    }
    for(int i = 1; i < N; i <<= 1) {
      for(int j = 0; j < N; j += i * 2) {
        for(int k = 0; k < i; k++) {
          int s = F[j + k], t = mul(F[j + k + i], rev ? rrts[i][k] : rts[i][k]);
          F[j + k] = add(s, t), F[j + k + i] = add(s, mod - t);
        }
      }
    }
    if(rev) {
      int temp = inverse(N);
      for(int i = 0; i < N; i++) F[i] = mul(F[i], temp);
    }
  }

  vector< int > Multiply(const vector< int > &A, const vector< int > &B) {
    int sz = 1;
    while(sz < A.size() + B.size() - 1) sz <<= 1;
    vector< int > F(sz), G(sz);
    for(int i = 0; i < A.size(); i++) F[i] = A[i];
    for(int i = 0; i < B.size(); i++) G[i] = B[i];
    DiscreteFourierTransform(F, false);
    DiscreteFourierTransform(G, false);
    for(int i = 0; i < sz; i++) F[i] = mul(F[i], G[i]);
    DiscreteFourierTransform(F, true);
    F.resize(A.size() + B.size() - 1);
    return F;
  }
};


const int mod=MOD;

inline int mul(int a, int b) {
  return int(1LL * a * b % mod);
}

inline int mod_pow(int x, int n) {
  int ret = 1;
  while(n > 0) {
    if(n & 1) ret = mul(ret, x);
    x = mul(x, x);
    n >>= 1;
  }
  return ret;
}

inline int inverse(int x) {
  return mod_pow(x, mod - 2);
}

inline int add(int x, int y) {
  x += y;
  if(x >= mod) x -= mod;
  return x;
}




int H,W;
const int lg=9;
const int MAX_SIZE=1<<lg;
NumberTheoreticTransform<MOD,3> NTT;
const int ms=4;

int A[MAX_SIZE][MAX_SIZE][ms][ms];
int mt[ms][ms];
int bk[ms][ms];
int ans[ms][ms];
vector<int> funcH,funcW;


void FFT_A(bool rev){
  for(int i=0;i<ms;i++){
    for(int j=0;j<ms;j++){
      for(int x=0;x<H;x++){
        for(int y=0;y<W;y++){
          funcW[y]=A[x][y][i][j];
        }
        NTT.DiscreteFourierTransform(funcW,rev);
        for(int y=0;y<W;y++){
          A[x][y][i][j]=funcW[y];
        }
      }
      for(int y=0;y<W;y++){
        for(int x=0;x<H;x++){
          funcH[x]=A[x][y][i][j];
        }
        NTT.DiscreteFourierTransform(funcH,rev);
        for(int x=0;x<H;x++){
          A[x][y][i][j]=funcH[x];
        }
      }
    }
  }
}

void cul(ll K){
  ll k;
  for(int x=0;x<H;x++){
    for(int y=0;y<W;y++){
      for(int i=0;i<ms;i++){
        for(int j=0;j<ms;j++){
          ans[i][j]=(i==j?1:0);
          mt[i][j]=A[x][y][i][j];
        }
      }
      k=K;
      while(k>0){
        if(k&1){
          for(int i=0;i<ms;i++){
            for(int j=0;j<ms;j++){
              bk[i][j]=0;
              for(int k=0;k<ms;k++){
                bk[i][j]=add(bk[i][j],mul(ans[i][k],mt[k][j]));
              }
            }
          }
          for(int i=0;i<ms;i++){
            for(int j=0;j<ms;j++){
              ans[i][j]=bk[i][j];
            }
          }
        }
        k>>=1;
        for(int i=0;i<ms;i++){
          for(int j=0;j<ms;j++){
            bk[i][j]=0;
            for(int k=0;k<ms;k++){
              bk[i][j]=add(bk[i][j],mul(mt[i][k],mt[k][j]));
            }
          }
        }
        for(int i=0;i<ms;i++){
          for(int j=0;j<ms;j++){
            mt[i][j]=bk[i][j];
          }
        }
      }
      for(int i=0;i<ms;i++){
        for(int j=0;j<ms;j++){
          A[x][y][i][j]=ans[i][j];
        }
      }
    }
  }
}


void init(){
  NTT.ensure_base(MAX_SIZE);
}



int main(){
  cin.tie(0);
  ios::sync_with_stdio(false);
  init();
  ll k;
  cin>>H>>W>>k;
  H=1<<H;
  W=1<<W;
  funcH.resize(H);
  funcW.resize(W);
  k++;
  A[0][0][0][0]=1;
  A[0][0][0][2]=1;
  vector<vector<int>> T(H,vector<int>(W));
  vector<vector<int>> G(H,vector<int>(W));
  cin>>T>>G;
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      if(T[i][j]==-1){continue;}
      for(int k=1;k<ms;k++){A[i][j][k][k]=add(A[i][j][k][k],1);}
      A[i][j][2][1]=add(A[i][j][2][1],mul(T[i][j],G[i][j]));
      A[i][j][2][3]=add(A[i][j][2][3],G[i][j]);
      A[i][j][3][1]=add(A[i][j][3][1],T[i][j]);
    }
  }
  FFT_A(false);
  cul(k);
  FFT_A(true);
  for(int i=0;i<H;i++){
    for(int j=0;j<W;j++){
      cout<<A[i][j][0][1];
      if(j+1!=W){cout<<" ";}
    }
    cout<<endl;
  }

  return 0;
}
accuracy: 1
time_ms: 1520
memory_kb: 21448
final_rank: 1