【PGBATTLE2020_せんべい4】ドミノ

過去問:https://products.sint.co.jp/q_list_2020
解答:https://products.sint.co.jp/hubfs/resource/topsic/pgb2020/code.pdf

解説を理解したあと実装した結果、解説コードと全く同じになりました。

・H=2のときフィボナッチ数列があらわれますが、ここからの発展性は見つかりませんでした。
・1をでっぱり、0を平坦とみなし、1<<5通りのhash同士について、凹凸が組み合わせられるか見ていきます。

Q. 凹凸の組み合わせ?
A. 

1 は横置き開始地点。0110 が遷移成立。
01. 1->0なら横置きの終端。
2. 0->0なら縦置き。0どうしが隣接していれば遷移成立。

Q. 3 6の場合。
1. DP[0][000]=1 からの状態遷移は3通り。
※(000)は本来ありえない。ただの初期条件
000 -> 001 
x      xa
x      xa
x      xbb
      
000 -> 100
x      xaa
x      xb
x      xb
      
000 -> 111
x      xaa
x      xbb
x      xcc

DP[1][001] = 1
DP[1][100] = 1
DP[1][111] = 1

2. もう一段思考整理
001 -> 000 
xa     xac
xa     xac
xbb    xbb

001 -> 110
xa     xacc
xa     xadd
xbb    xbb


100 -> 000 
xaa    xaa
xb     xbc
xb     xbc

100 -> 011
xaa    xaa
xb     xbcc
xb     xbdd


111 -> 000
xaa    xaa
xbb    xbb
xcc    xcc

DP[2][000] = 3
DP[2][110] = 1
DP[2][011] = 1
になる。

A. 
(3, 6)
41
000:1 0 3 0 11 0 41 
001:0 1 0 4 0 15 0 
010:0 0 0 0 0 0 0 
011:0 0 1 0 4 0 15 
100:0 1 0 4 0 15 0 
101:0 0 0 0 0 0 0 
110:0 0 1 0 4 0 15 
111:0 1 0 3 0 11 0 

Q. 00の縦置きが成立する条件?
A.

0が縦置きだとすると

10000
00100
00001
11100
11001
10011
00111

といった、0が2個隣接したような置き方。

101 は縦置きできないとみなす。
010 も。

組み合わせ方がわかれば、
DP[index][hash]=組み合わせ数で管理。
初期条件はDP[0][00000]=1
解答はDP[W][00000]

実装

bool matrix[1<<5][1<<5]; // pre, nx
map<ll, bool> goodhash; // goodhash[hash]=true なら縦置き状態遷移できる
ll DP[10010][1<<5];
ll H, W;

void debug(){
 rep(j, (1<<H)){
   string bits;
   rep(k, 5){
     if((j>>k)&1) bits+="1";
     else bits+="0";
   }
   reverse(all(bits));
   cout << bits << ":";
   rep(i, W+1){
     cout << DP[i][j] << " ";
   }
   cout << endl;
 }
}

int main(){
 cincout();
 
 cin >> H >> W;
 if(H%2 && W%2){
   cout << 0 << endl;
   return 0;
 }
 // goodhash
 rep(i, (1<<H)){
   vector<ll> pos;
   ll cnts = __builtin_popcountll(i);
   if(cnts%2) continue;
   rep(h, H){
     if ((i>>h)&1) pos.push_back(h);
   }
   bool ok=true;
   rep(c, cnts/2){
     if(pos[c*2] != pos[c*2+1]-1) ok=false;
   }
   if(ok) goodhash[i] = true;
 }
 
 // matrix 凹凸が成立する組み合わせかどうか
 rep(pre, (1<<H)){
   rep(nx, (1<<H)){
     //11はありえない
     //00の縦置きができるか判定
     ll check=0;
     rep(h, H){
       if ( ispop(pre, h) && ispop(nx, h) ) check=oo;
       if ( !ispop(pre, h) && !ispop(nx, h) ) check |= 1<<h;
     }
     if (goodhash.count(check)) matrix[pre][nx] = true;
   }
 }
 
 DP[0][0]=1;
 rep(i, W){
   rep(pre, (1<<H)){
     rep(nx, (1<<H)){
       if(matrix[pre][nx]) ( DP[i+1][nx] += DP[i][pre] ) %= MOD;
     }
   }
 }
 cout << DP[W][0] << endl;
//  debug();
}



いいなと思ったら応援しよう!