競技プログラミング日記

主に AtCoder の記事です

アルゴリズムと数学057 - Domino Tiling

アルゴリズムと数学057 - Domino Tiling

解法: 行列冪乗

これも遷移が線形になるので,行列冪で解ける. 状態を \(2^{K}\) で持っておき, 次数\(2^{K}\)の行列を考える.
まず\(N\)が小さい場合で考えてみる. DP による全探索をすると, 左から \(i\) 列目を決めるときは, \(i-1\) 列目の配置によってのみ影響を受ける. 実際,\(i-1\) 列目を敷き詰めるとき, \(i\) 列目においてどの場所にはみ出したかで, \(i\) 列目の敷き詰め方が決まる.
(\(k \in K\) 列目においてはみ出しているか) \(\in 2\) と考えれば, 状態が \(2^{K}\) となる. これは 2進数で考えるとよい. 例えば\(K=4\)のとき,

    xy
  1 **
0 *
0 *
  1 **

の様な形になる.\(x\)が今の行,\(y\)が次の行. 次の行にはみ出している部分だけ \(1\), それ以外は \(0\) を割り当ててて, 2進数 \(1001\) を対応させる.

使っている記号,マクロ等 "https://ecsmtlir.hatenablog.com/entry/2022/12/23/131925"

int main() {
  ll k; cin >> k;

  ll n;
  cin >> n;

  if(k == 2){
    Matrix<mint> a2(vector<vector<mint>>{
      {1,0,0,1},
      {0,0,1,0},
      {0,1,0,0},
      {1,0,0,0}
    });

    Matrix<mint> ini(vector<vector<mint>>{
      {1,0,0,0}
    });

    cout << (ini*a2.pow(n)).get(0,0).val() << endl;

  }else if(k == 3){
    Matrix<mint> a3(vector<vector<mint>>{
      {0,1,0,0, 1,0,0,1},
      {1,0,0,0, 0,0,1,0},
      {0,0,0,0, 0,1,0,0},
      {0,0,0,0, 1,0,0,0},

      {1,0,0,1, 0,0,0,0},
      {0,0,1,0, 0,0,0,0},
      {0,1,0,0, 0,0,0,0},
      {1,0,0,0, 0,0,0,0},
    });

    Matrix<mint> ini(vector<vector<mint>>{
      {1,0,0,0, 0,0,0,0}
    });

    cout << (ini*a3.pow(n)).get(0,0).val() << endl;
   
  }else if(k == 4){
    Matrix<mint> a4(vector<vector<mint>>{
      {1,0,0,1, 0,0,0,0, 0,1,0,0, 1,0,0,1},
      {0,0,1,0, 0,0,0,0, 1,0,0,0, 0,0,1,0},
      {0,1,0,0, 0,0,0,0, 0,0,0,0, 0,1,0,0},
      {1,0,0,0, 0,0,0,0, 0,0,0,0, 1,0,0,0},
      {0,0,0,0, 0,0,0,0, 1,0,0,1, 0,0,0,0},
      {0,0,0,0, 0,0,0,0, 0,0,1,0, 0,0,0,0},
      {0,0,0,0, 0,0,0,0, 0,1,0,0, 0,0,0,0},
      {0,0,0,0, 0,0,0,0, 1,0,0,0, 0,0,0,0},
     
      {0,1,0,0, 1,0,0,1, 0,0,0,0, 0,0,0,0},
      {1,0,0,0, 0,0,1,0, 0,0,0,0, 0,0,0,0},
      {0,0,0,0, 0,1,0,0, 0,0,0,0, 0,0,0,0},
      {0,0,0,0, 1,0,0,0, 0,0,0,0, 0,0,0,0},

      {1,0,0,1, 0,0,0,0, 0,0,0,0, 0,0,0,0},
      {0,0,1,0, 0,0,0,0, 0,0,0,0, 0,0,0,0},
      {0,1,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0},
      {1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}
    });

    Matrix<mint> ini(vector<vector<mint>>{
      {1,0,0,0, 0,0,0,0, 0,0,0,0, 0,0,0,0}
    });

    cout << (ini*a4.pow(n)).get(0,0).val() << endl;
   
  }

  return 0;
}