Problem:
B: テトリス

問題

縦 4 マス x 横 10 マスの長方形からなる盤面を考えます。
縦 1 マス x 横 1 マスぶんの正方形をブロックと呼びます。

ブロックを 4 つ繋げたものをテトロミノと呼び、以下の 7 種類（およびこれらに対して 90 度回転を任意回行ったもの）があります。

さて、盤面のうち 28 個のマスにブロックが置かれた状態を考えます。

左の図のように、各ブロック（赤色で表される）はマスに合うように置かれます。右の図のように半端な位置に置かれることはありません。

4 つのテトロミノ t_1, t_2, t_3, t_4 が与えられるので、このうちちょうど 3 つを選んですきな位置に置くことで、盤面全体にブロックが置かれた状態にできるか判定してください。

ただし、テトロミノを配置するにあたり、以下の条件をすべて満たさなければなりません。

ブロック同士が重なってはいけない。

与えられたテトロミノを回転させてはいけない。

各 i (1 \leq i \leq 4) について、テトロミノ t_i を 2 回以上使ってはいけない。

テトロミノの各ブロックは盤面の外に出てはいけない。

盤面が n 個与えられるので、各盤面についてこの判定を行い、盤面全体にブロックを置けるならば Yes、不可能ならば No を出力してください。

入力形式

t_1
t_2
t_3
t_4
n
B_1
…
B_n

はじめに、使えるテトロミノ t_1, t_2, t_3, t_4 が与えられます。
各 t_i (1 \leq i \leq 4) は以下の形式で与えられます。

h w
s_1
…
s_h

これはテトロミノを含む縦 h x 横 w マスの長方形であり、テトロミノの形状は s_1 … s_h で表されます。長方形のうち、テトロミノを表す部分は #、それ以外の部分は . で表されます。各長方形に # はちょうど 4 つ含まれます。. のみからなる行または列は存在しません。

次に、盤面の個数 n が与えられます。
その後、4\times 10 マスで表される盤面 B が n 個与えられます。
ブロックがある位置が #、ない位置が . で示されます。

制約

1\leq n\leq 10^5

与えられる各テトロミノは上で述べた条件に違反しない

各盤面について、# はちょうど 28 個存在する

たとえば、以下のようなテトロミノは与えられない。

3 3
..#
.#.
##.

（連結でないブロックがあり、これは上で述べたテトロミノの条件を満たさない）

3 3
...
.#.
###

（一番上の行が . のみからなる）

出力形式

n 行にわたって出力してください。i 行目には盤面 B_i に対する判定結果を Yes または No で出力してください。

入力例1

2 3
##.
.##
2 3
#..
###
1 4
####
2 3
###
.#.
2
####....##
####...###
####..####
####...###
###..#####
###...####
###...####
###....###

出力例1

Yes
Yes

t_1, t_2, t_3, t_4 に相当するテトロミノが置かれる場所をそれぞれ 1, 2, 3, 4 で示すと、各盤面は次のように敷き詰められます。

####3333##
####444###
####24####
####222###

###11#####
###211####
###222####
###3333###

各盤面について、別々のテトロミノを選んで構いません。

入力例2

1 4
####
1 4
####
2 2
##
##
2 2
##
##
4
######....
....######
#######..#
#######..#
....######
######....
....######
##########
######.#.#
######.#.#
##..##.#.#
##..##.#.#
##.###.#.#
#.#.###.##
#.#.###.##
##.###.#.#

出力例2

Yes
No
No
No

#### が足りないため、2 つ目の盤面をブロックで敷き詰めることはできません。

また、テトロミノを回転させることはできないので、3 つ目の盤面を敷き詰めることもできません。

また、4 つ目の盤面のようなブロックの配置の仕方もありえることに注意してください。すなわち、入力で与えられる盤面はテトロミノを組み合わせて作られる盤面とは限りません。

Solution in C++14 (judge verdict: Accepted)

#include<bits/stdc++.h>
using namespace std;
#define lp(i,n) for(int i=0;i<n;i++)
#define lps(i,j,n) for(int i=j;i<n;i++)
#define fordebug int hoge;cin>>hoge;
#define DEKAI 1000000007
#define INF 2000000000000
#define int long long
#define double long double
#define floot10 cout<<fixed<<setprecision(10)
#define Int long long
#define ALL(n) n.begin(),n.end()
#define hogea pair<pair<int,int>,int>

struct field{
  string s[4];
  field(){};
  field(string s1,string s2,string s3,string s4){
    s[0]=s1;
    s[1]=s2;
    s[2]=s3;
    s[3]=s4;
  };
};

string ms(field f){
  string s=f.s[0]+f.s[1]+f.s[2]+f.s[3];
  return s;
}

struct teto{
  string s[4];
  int h,w;
};

teto t[4];
set<string> lis;

void revs(int n){
  teto x;
  x.h=t[n].w;
  x.w=t[n].h;
  lp(i,x.h){
    string s="";
    lp(j,t[n].h){
      s=s+t[n].s[j].substr(i,1);
    }
    x.s[i]=s;
  }
  t[n]=x;
}

field br(field f,int n,int x,int y){
  for(int i=x;i<x+t[n].h;i++){
    for(int j=y;j<y+t[n].w;j++){
      if(t[n].s[i-x][j-y]=='#'){
	f.s[i][j]='.';
      }
    }
  }
  return f;
}

bool brcheck(field f,int n,int x,int y){
  for(int i=x;i<x+t[n].h;i++){
    if(i>=4)return false;
    for(int j=y;j<y+t[n].w;j++){
      if(j>=10)return false;
      if(t[n].s[i-x][j-y]=='#'){
	if(f.s[i][j]=='.')return false;
      }
    }
  }
  return true;
}

int popcount(int n){
  int cnt=0;
  lp(i,64){
    if(n&(1<<1))cnt++;
  }
  return cnt;
}

void DBD(field f){
  lp(i,4){
    cout<<f.s[i]<<endl;
  }
  return;
}

void hoge(field f,int b){
  if(__builtin_popcount(b)==3){
    lis.insert(ms(f));
    /*DBD(f);
    int hoge;
    cin>>hoge;*/
    return;
  }
  lp(z,4){
    if(b&(1<<z))continue;
    lp(i,10){
      lp(j,10){
	if(brcheck(f,z,i,j)){
	  hoge(br(f,z,i,j),b|(1<<z));
	}
      }
    }
  }
}

void make(){
  field f("##########","##########","##########","##########");
  hoge(f,0);
}

signed main(){
  lp(i,4){
    int h,w;
    cin>>h>>w;
    t[i].h=h;
    t[i].w=w;
    lp(j,h){
      string s;
      cin>>s;
      t[i].s[j]=s;
    }
  }
  make();
  int n;
  cin>>n;
  lp(i,n){
    string s[4];
    lp(j,4){
      cin>>s[j];
    }
    field f(s[0],s[1],s[2],s[3]);
    if(lis.find(ms(f))==lis.end()){
      cout<<"No"<<endl;
    }
    else cout<<"Yes"<<endl;
  }
  return 0;
}