Problem:
Pipeline Plans
There are twelve types of tiles in Fig. 1.
 You were asked to fill a table with
R × C
cells with these tiles.
R
is the number of rows and
C
is the number of columns.
How many arrangements in the table meet the following constraints?
Each cell has one tile.
the center of the upper left cell (1,1) and the center of the lower right cell (
C
,
R
) are connected by some roads.
Fig. 1: the types of tiles
Input
The first line contains two integers
R
and
C
(2 ≤ R × C ≤ 15)
.
You can  safely assume at least one of
R
and
C
is greater than 1.
The second line contains twelve integers,
t
1
,
t
2
, ...,
t
12
(0 ≤ t
1
+ .... + t
12
≤ 15)
.
t
i
represents the number of the
i
-th tiles you have.
Output
Output the number of arrangments in a line.
Sample Input 1
3 3
4 2 2 0 0 0 0 0 0 0 0 1
Output for the Sample Input 1
2
Sample Input 2
3 3
0 1 1 0 0 0 0 0 0 0 0 7
Output for the Sample Input 2
66
Sample Input 3
3 3
0 0 0 0 0 0 0 0 0 0 0 10
Output for the Sample Input 3
1
Sample Input 4
2 4
0 0 1 1 1 2 0 1 0 0 1 1
Output for the Sample Input 4
2012
Sample Input 5
5 2
0 1 1 1 0 1 2 1 2 0 0 1
Output for the Sample Input 5
8512

Submitted solutions:

code_snippet: #include <iostream>
#include <cstring>

#pragma GCC optimize(2)

using namespace std;

using i64 = long long;

const int N = 1000000, M = 9979; 
const int offset = 3, mask = 7;

int num[8], a[8], bk[8];
int n, m, c[15];
int s1, f;
i64 s2;
int l, u, r, d;
i64 v;
int tot;
i64 res;
bool ed;
struct Hash_Table {
    int h[M], ne[N], idx;
    int state[N];
    i64 used[N], val[N];
    int flag[N];
    
    void init() { 
        idx = 0, memset(h, -1, sizeof h); 
    }
    
    void push(int s1, i64 s2, int f, i64 v) {
        int x = s2 % M;
        for (int i = h[x]; ~i; i = ne[i])
            if (state[i] == s1 && flag[i] == f && used[i] == s2)
                return (val[i] += v), void();
        state[idx] = s1, used[idx] = s2, flag[idx] = f, val[idx] = v;
        ne[idx] = h[x], h[x] = idx++; 
    }
    
    void roll() {
        for (int i = 0; i < idx; i++)
            state[i] <<= offset;
    }
} h[2], *h0, *h1;

void decode() {
    for (int i = 0; i <= m; i++)
        a[i] = s1 & mask, s1 >>= offset;
}

struct State {
    int s1; 
    int f;
};

State encode(int f) {
    memset(num, -1, sizeof num);
    int k = 0, s1 = 0;
    num[0] = 0;
    for (int i = m; ~i; i--) {
        if (!~num[a[i]])
            num[a[i]] = ++k;
        s1 = (s1 << offset) | num[a[i]];
    }
    f = num[f];
    return {s1, f};
}

void add(int s1, i64 s2, int f, i64 v) {
    h1->push(s1, s2, f, v); 
}

void change(int x, int y) {
    for (int i = 0; i < m + 1; i++)
        if (a[i] == x)
            a[i] = y;
}

void add(int j, int t, i64 v, i64 ns2) {
    memcpy(bk, a, sizeof a);
    int bkf = f;
    if (t == 1) r = d = 0;
    if (t == 2) {
        if (ed && u == bkf) res += v;
        if (u) d = u, r = 0;
        else d = mask, r = 0;
    }
    if (t == 3) {
        if (ed && l == bkf) res += v;
        if (l) r = l, d = 0;
        else r = mask, d = 0;
    }
    if (t == 4) {
        if (ed && u == bkf) res += v;
        if (u) r = u, d = 0;
        else r = mask, d = 0;
    }
    if (t == 5) {
        r = d = mask;
    }
    if (t == 6) {
        if (ed && l == bkf) res += v;
        if (l) d = l, r = 0;
        else d = mask, r = 0;
    }
    if (t == 7) {
        if (ed && (l == bkf || u == bkf)) res += v;
        if (u && l) {
            change(u, l);
            if (f == u) f = l;
        } 
        d = r = 0;
    }
    if (t == 8) {
        if (ed && u == bkf) res += v;
        if (u) d = r = u;
        else d = r = mask;
    }
    if (t == 9) {
        if (ed && l == bkf) res += v;
        if (l) d = r = l;
        else d = r = mask;
    }
    if (t == 10) {
        if (ed && (l == bkf || u == bkf)) res += v;
        if (u && l) {
            change(u, l);
            if (f == u) f = l;
            d = l, r = 0;
        } else if (u || l) {
            int t = u | l;
            d = t, r = 0;
        } else {
            d = mask, r = 0;
        }
    }
    if (t == 11) {
        if (ed && (l == bkf || u == bkf)) res += v;
        if (u && l) {
            change(u, l);
            if (f == u) f = l;
            d = 0, r = l;
        } else if (u || l) {
            int t = u | l;
            d = 0, r = t;
        } else {
            d = 0, r = mask;
        }
    }
    if (t == 12) {
        if (ed && (l == bkf || u == bkf)) res += v;
        if (u && l) {
            change(u, l);
            if (f == u) f = l;
            d = r = l;
        } else if (u || l) {
            int t = u | l;
            d = r = t;
        } else {
            d = r = mask;
        }
    }
    a[j] = d, a[j + 1] = r;
    State S = encode(f);
    int ns1 = S.s1, nf = S.f;
    if (nf > 0) add(ns1, ns2, nf, v); 
    memcpy(a, bk, sizeof a);
    f = bkf;
}

void trans(int i, int j) {
    swap(h1, h0);
    h1->init();
    for (int k = 0; k < h0->idx; k++) {
        s1 = h0->state[k];
        s2 = h0->used[k];
        f = h0->flag[k];
        v = h0->val[k];  
        decode();
        l = a[j], u = a[j + 1];
        if (i == n - 1 && j == m - 1) ed = true;
        for (int p = 1; p <= 12; p++) {
            i64 t = s2 >> (p << 2) & 15;
            if (t) { 
                i64 ns2 = s2;
                ns2 &= ~(15ll << (p << 2));
                ns2 |= (t - 1) << (p << 2);
                add(j, p, v, ns2);
            }
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= 12; i++) {
        cin >> c[i];
    }   
    if (n < m) {
        swap(n, m);
        swap(c[2], c[3]);
        swap(c[4], c[6]);
        swap(c[8], c[9]);
        swap(c[10], c[11]);
    }  
    i64 s2 = 0;
    for (int i = 1; i <= 12; i++) s2 |= ((1ll * c[i]) << (4 * i));
    h0 = h, h1 = h + 1;
    h1->init();
    h1->push(0, s2, mask, 1);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) {
            trans(i, j);
        }
        h1->roll();
    }
    cout << res << '\n';
    return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 30228
final_rank: 3

code_snippet: #include <iostream>
#include <cstring>
#include <vector>
#include <cassert>

using namespace std;

using i64 = long long;

const int N = 200000, M = 9979; 
const int mask = 7;

int num[8], a[8], bk[8];
int n, m;
int c[15], b[15];
int s1, l, u, r, d;
i64 s2, v, res;
bool st, ed;

struct Hash_Table {
    int h[M], ne[N], idx;
    int state[N];
    i64 used[N], val[N];
    
    void init() { 
        idx = 0, memset(h, -1, sizeof h); 
    }
    
    void push(int s1, i64 s2, i64 v) {
        int x = s2 % M;
        for (int i = h[x]; ~i; i = ne[i])
            if (state[i] == s1 && used[i] == s2)
                return (val[i] += v), void();
        state[idx] = s1, used[idx] = s2, val[idx] = v;
        ne[idx] = h[x], h[x] = idx++; 
    }
    
    void roll() {
        for (int i = 0; i < idx; i++) state[i] <<= 3;
    }
} h[2], *h0, *h1;

void decode() {
    for (int i = 0; i <= m; i++) a[i] = s1 & 7, s1 >>= 3;
    for (int i = 1; i <= 12; i++) b[i] = s2 & 15, s2 >>= 4;
}

pair<int, i64> encode() {
    memset(num, -1, sizeof num);
    int k = 1, s1 = 0;
    i64 s2 = 0;
    num[0] = 0, num[1] = 1;
    bool f = false;
    for (int i = m; ~i; i--) {
        if (num[a[i]] == -1) num[a[i]] = ++k;
        s1 = (s1 << 3) | num[a[i]];
        if (a[i] == 1) f = true;
        assert(num[a[i]] <= 7);
    }
    for (int i = 12; i; i--) s2 = (s2 << 4) | b[i];
    return {f ? s1 : -1, s2};
}

void add(int s1, i64 s2, i64 v) {
    h1->push(s1, s2, v); 
}

void change(int& x, int& y) {
    if (x == 1) swap(x, y);
    for (int i = 0; i < m + 1; i++) 
        if (a[i] == x)
            a[i] = y;
}

void add(int j, int t, i64 v) {
    memcpy(bk, a, sizeof a);
    if (t == 1) r = d = 0;
    if (t == 2) {
        if (ed && u == 1) res += v;
        if (u) d = u, r = 0;
        else d = st ? 1 : mask, r = 0;
    }
    if (t == 3) {
        if (ed && l == 1) res += v;
        if (l) r = l, d = 0;
        else r = st ? 1 : mask, d = 0;
    }
    if (t == 4) {
        if (ed && u == 1) res += v;
        if (u) r = u, d = 0;
        else r = st ? 1 : mask, d = 0;
    }
    if (t == 5) {
        r = d = st ? 1 : mask;
    }
    if (t == 6) {
        if (ed && l == 1) res += v;
        if (l) d = l, r = 0;
        else d = st ? 1 : mask, r = 0;
    }
    if (t == 7) {
        if (ed && (l == 1 || u == 1)) res += v;
        if (u && l) change(u, l);
        d = r = 0;
    }
    if (t == 8) {
        if (ed && u == 1) res += v;
        if (u) d = r = u;
        else d = r = (st ? 1 : mask);
    }
    if (t == 9) {
        if (ed && l == 1) res += v;
        if (l) d = r = l;
        else d = r = (st ? 1 : mask);
    }
    if (t == 10) {
        if (ed && (l == 1 || u == 1)) res += v;
        if (u && l) {
            change(u, l);
            d = l, r = 0;  
        } else if (u || l) {
            d = (u | l), r = 0;
        } else {
            d = (st ? 1 : mask), r = 0;
        }
    }
    if (t == 11) {
        if (ed && (l == 1 || u == 1)) res += v;
        if (u && l) {
            change(u, l);
            d = 0, r = l;
        } else if (u || l) {
            d = 0, r = (u | l);
        } else {
            d = 0, r = (st ? 1 : mask);
        }
    }
    if (t == 12) {
        if (ed && (l == 1 || u == 1)) res += v;
        if (u && l) {
            change(u, l);   
            d = r = l; 
        } else if (u || l) {
            d = r = (u | l);
        } else {
            d = r = (st ? 1 : mask);
        }
    }
    a[j] = d, a[j + 1] = r;
    pair<int, i64> p = encode();
    s1 = p.first;
    s2 = p.second;
    memcpy(a, bk, sizeof a);
    if (~s1) add(s1, s2, v);
}

void trans(int i, int j) {
    swap(h1, h0);
    h1->init();
    if (i == n - 1 && j == m - 1) ed = true;
    if (i == 0 && j == 0) st = true;
    else st = false;
    // cout << h0->idx << '\n';
    for (int k = 0; k < h0->idx; k++) {
        s1 = h0->state[k], s2 = h0->used[k], v = h0->val[k];  
        decode();
        for (int p = 1; p <= 12; p++) if (b[p]) {
            l = a[j], u = a[j + 1];
            b[p]--, add(j, p, v), b[p]++;
        }
    }
}

int main() {
    cin >> n >> m;
    for (int i = 1; i <= 12; i++) cin >> c[i];
    if (n < m) swap(n, m), swap(c[2], c[3]), swap(c[4], c[6]), swap(c[8], c[9]), swap(c[10], c[11]);
    for (int i = 12; i; i--) s2 = (s2 << 4) | c[i];
    h0 = h, h1 = h + 1;
    h1->init(), h1->push(0, s2, 1);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < m; j++) trans(i, j);
        h1->roll();
    }
    cout << res << '\n';
    return 0;
}
accuracy: 1
time_ms: 250
memory_kb: 11236
final_rank: 1

code_snippet: #pragma GCC optimize("O3")
#pragma GCC optimize("unroll-loops")
#include<iostream>
#include<string>
#include<cstdio>
#include<vector>
#include<cmath>
#include<algorithm>
#include<functional>
#include<iomanip>
#include<queue>
#include<ciso646>
#include<random>
#include<map>
#include<set>
#include<bitset>
#include<stack>
#include<unordered_map>
#include<unordered_set>
#include<utility>
#include<cassert>
#include<complex>
#include<numeric>
#include<array>
#include<chrono>
using namespace std;

//#define int long long
typedef long long ll;

typedef unsigned long long ul;
typedef unsigned int ui;
constexpr ll mod = 1000000007;
const ll INF = mod * mod;
typedef pair<int, int>P;

#define rep(i,n) for(int i=0;i<n;i++)
#define per(i,n) for(int i=n-1;i>=0;i--)
#define Rep(i,sta,n) for(int i=sta;i<n;i++)
#define rep1(i,n) for(int i=1;i<=n;i++)
#define per1(i,n) for(int i=n;i>=1;i--)
#define Rep1(i,sta,n) for(int i=sta;i<=n;i++)
#define all(v) (v).begin(),(v).end()
typedef pair<ll, ll> LP;

template<typename T>
void chmin(T& a, T b) {
	a = min(a, b);
}
template<typename T>
void chmax(T& a, T b) {
	a = max(a, b);
}
template<typename T>
void cinarray(vector<T>& v) {
	rep(i, v.size())cin >> v[i];
}
template<typename T>
void coutarray(vector<T>& v) {
	rep(i, v.size()) {
		if (i > 0)cout << " "; cout << v[i];
	}
	cout << "\n";
}
ll mod_pow(ll x, ll n, ll m = mod) {
	if (n < 0) {
		ll res = mod_pow(x, -n, m);
		return mod_pow(res, m - 2, m);
	}
	if (abs(x) >= m)x %= m;
	if (x < 0)x += m;
	if (x == 0)return 0;
	ll res = 1;
	while (n) {
		if (n & 1)res = res * x % m;
		x = x * x % m; n >>= 1;
	}
	return res;
}
struct modint {
	int n;
	modint() :n(0) { ; }
	modint(ll m) {
		if (m < 0 || mod <= m) {
			m %= mod; if (m < 0)m += mod;
		}
		n = m;
	}
	operator int() { return n; }
};
bool operator==(modint a, modint b) { return a.n == b.n; }
modint operator+=(modint& a, modint b) { a.n += b.n; if (a.n >= mod)a.n -= mod; return a; }
modint operator-=(modint& a, modint b) { a.n -= b.n; if (a.n < 0)a.n += mod; return a; }
modint operator*=(modint& a, modint b) { a.n = ((ll)a.n * b.n) % mod; return a; }
modint operator+(modint a, modint b) { return a += b; }
modint operator-(modint a, modint b) { return a -= b; }
modint operator*(modint a, modint b) { return a *= b; }
modint operator^(modint a, ll n) {
	if (n == 0)return modint(1);
	modint res = (a * a) ^ (n / 2);
	if (n % 2)res = res * a;
	return res;
}

ll inv(ll a, ll p) {
	return (a == 1 ? 1 : (1 - p * inv(p % a, a)) / a + p);
}
modint operator/(modint a, modint b) { return a * modint(inv(b, mod)); }
modint operator/=(modint& a, modint b) { a = a / b; return a; }
const int max_n = 1 << 10;
modint fact[max_n], factinv[max_n];
void init_f() {
	fact[0] = modint(1);
	for (int i = 0; i < max_n - 1; i++) {
		fact[i + 1] = fact[i] * modint(i + 1);
	}
	factinv[max_n - 1] = modint(1) / fact[max_n - 1];
	for (int i = max_n - 2; i >= 0; i--) {
		factinv[i] = factinv[i + 1] * modint(i + 1);
	}
}
modint comb(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[b] * factinv[a - b];
}
modint combP(int a, int b) {
	if (a < 0 || b < 0 || a < b)return 0;
	return fact[a] * factinv[a - b];
}

ll gcd(ll a, ll b) {
	a = abs(a); b = abs(b);
	if (a < b)swap(a, b);
	while (b) {
		ll r = a % b; a = b; b = r;
	}
	return a;
}

typedef long double ld;
typedef pair<ld, ld> LDP;
const ld eps = 1e-8;
const ld pi = acosl(-1.0);
int dx[4] = { 1,0,-1,0 };
int dy[4] = { 0,1,0,-1 };

vector<vector<int>> vs;
void init(int h) {
	vector<int> cur;
	function<void(int)> dfs = [&](int s) {
		if (s == (1 << (h + 1)) - 1) {
			vector<int> col(h + 1);
			rep(i, cur.size())rep(j, h + 1)if (cur[i] & (1 << j)) {
				col[j] = i;
			}
			vs.push_back(col);
			return;
		}
		int low = -1;
		rep(i, h + 1) {
			if (s & (1 << i))continue;
			low = i; break;
		}
		rep(i, (1 << (h + 1))) {
			if (i == 0)continue;
			if (s & i)continue;
			if (s > 0 && !(i & (1 << low)))continue;
			cur.push_back(i);
			dfs(s | i);
			cur.pop_back();
		}
	};
	dfs(0);
	sort(all(vs));
}
int trans(vector<int> col) {
	bool exi = false;
	rep(i, col.size())if (col[i] == 0)exi = true;
	if (!exi)return -1;
	vector<int> res = col;
	vector<bool> used(col.size());
	int tmp = 1;
	rep(i, col.size()) {
		if (col[i] == 0)continue;
		if (used[i])continue;
		res[i] = tmp;
		Rep(j, i + 1, col.size()) {
			if (col[i] == col[j]) {
				res[j] = tmp;
				used[j] = true;
			}
		}
		tmp++;
	}
	int ret= lower_bound(all(vs), res) - vs.begin();
	assert(ret < (int)vs.size()&&vs[ret]==res);
	return ret;
}
ll dp[1 << 15][37];
ll cop[1 << 15][37];

bool bup[12] = { 0,1,0,1,0,0,1,1,0,1,1,1 };
bool bdw[12] = { 0,1,0,0,1,1,0,1,1,1,0,1 };
bool ble[12] = { 0,0,1,0,0,1,1,0,1,1,1,1 };
bool bri[12] = { 0,0,1,1,1,0,0,1,1,0,1,1 };
int rev[12] = { 0,2,1,5,4,3,6,8,7,10,9,11 };

bool ok[1 << 15][15];
void solve() {
	//cout << vs.size() << "\n";
	int h, w; cin >> h >> w;
	bool sw = false;
	if (h > w) {
		swap(h, w);
		sw = true;
	}
	init(h);
	vector<int> c;
	rep(i, 12) {
		int x; cin >> x;
		rep(j, x) {
			if (sw)c.push_back(rev[i]);
			else c.push_back(i);
		}
	}
	sort(all(c));
	rep(i, (1 << c.size()))rep(j, c.size()) {
		if (i & (1 << j))continue;
		ok[i][j] = true;
		if (j > 0 && c[j - 1] == c[j]) {
			if (!(i & (1 << (j - 1))))ok[i][j] = false;
		}
	}
	int len = c.size();
	int sz = vs.size();
	ll ans = 0;
	
	vector<int> ori(h + 1);
	rep(i, h)ori[i] = i + 1; ori[h] = 0;
	//cout << trans(ori) << "\n";
	dp[0][trans(ori)] = 1;
	rep(j, w) {
		rep(i, h) {
			rep(x, (1 << len))rep(y, sz) {
				cop[x][y] = 0;
			}
			rep(x, (1 << len))rep(y,sz) {
				if (dp[x][y] == 0)continue;
				rep(nex, len) {
					if (x & (1 << nex))continue;
					if (!ok[x][nex])continue;
					vector<int> nw = vs[y];
					int scol = 50;
					if (i == 0 && j == 0)scol = 0;
					else {
						vector<int> pre;
						//from upper
						if (i > 0 && bup[c[nex]])pre.push_back(nw[h]);
						//from left
						if (ble[c[nex]])pre.push_back(nw[i]);
						if (pre.size() == 2) {
							int mi = min(pre[0], pre[1]);
							rep(k, nw.size()) {
								if (nw[k] == pre[0] || nw[k]==pre[1]) {
									nw[k] = mi;
								}
							}
							scol = mi;
						}
						else if (pre.size() == 1)scol = pre[0];
					}
					if (i == h - 1 && j == w - 1) {
						if (scol == 0)ans += dp[x][y];
						continue;
					}
					if (bri[c[nex]])nw[i] = scol;
					else nw[i] = 100;
					if (bdw[c[nex]])nw[h] = scol;
					else nw[h] = 200;
					int nx = x ^ (1 << nex);
					int ny = trans(nw);
					if (ny >= 0) {
						cop[nx][ny] += dp[x][y];
					}
				}
			}


			rep(x, (1 << len))rep(y, sz) {
				dp[x][y] = cop[x][y];
			}
		}
	}
	cout << ans << "\n";
}


signed main() {
	ios::sync_with_stdio(false);
	cin.tie(0);
	cout << fixed << setprecision(8);
	//init_f();
	//init();
	//while(true)
	//expr();
	//int t; cin >> t; rep(i, t)
	solve();
	return 0;
}
accuracy: 1
time_ms: 190
memory_kb: 22844
final_rank: 2

code_snippet: #include<bits/stdc++.h>
using namespace std;
#define rep(i,n) for(int i=0;i<(int)(n);i++)
typedef long long ll;
int piece[]={0,5,10,9,12,6,3,13,14,7,11,15};
int edge[]={-7,-1,7,1};

class UnionFind{
private:
    int sz;
    vector<int> par,nrank;
public:
    UnionFind(){}
    UnionFind(int node_size): sz(node_size),par(sz),nrank(sz,0){
        iota(par.begin(),par.end(),0);
    }
    int find(int x){
        if(par[x]==x)return x;
        else return par[x] = find(par[x]);
    }
    void unite(int x,int y){
        x = find(x),y = find(y);
        if(x==y)return ;
        if(nrank[x] < nrank[y]) swap(x,y);
        par[y] = x;
        if(nrank[x] == nrank[y]) nrank[x]++;
    }
    bool same(int x,int y){
        return find(x) == find(y);
    }
};

void trans(vector<int>&t){
    swap(t[1],t[2]);
    swap(t[3],t[5]);
    swap(t[7],t[8]);
    swap(t[9],t[10]);
}
int hsh(vector<int>&a,vector<int>&t){
    int tmp = 0;
    int p = 1;
    rep(i,a.size()){
        tmp += p*a[i];
        p *= 3;
    }   
    rep(i,t.size()){
        tmp += p*t[i];
        p*=12; 
    }
    return tmp;
}

int in[]={1,3,5};
int mid[]={8,10,12};
int out[]={15,17,19};

vector<int> func(vector<int>&a,vector<int>&t){
    int n = a.size();
    UnionFind uf(21);
    rep(i,n){
        rep(j,n){
            if(a[i]==a[j]){
                uf.unite(in[i],in[j]);
            }
        }
    }
    rep(i,n){
        rep(k,4){
            if((piece[t[i]]>>k)&1){
                uf.unite(mid[i],mid[i] + edge[k]);
            }
        }
    }
    vector<int> b(n,-1);
    rep(i,n){
        if(a[i]==0){
            rep(j,n){
                if(uf.same(in[i],out[j])){
                    b[j] = 0;
                }
            }
        }
    }
    int c = 1;
    rep(i,n){
        if(b[i]==-1){
            b[i] = c;
            for(int j=i+1;j<n;j++){
                if(uf.same(out[i],out[j])){
                    b[j] = c;
                }
            }
            c++;
        }
    }
    // cerr << "a: ";
    // rep(i,n){
    //     cerr << a[i] << " ";
    // }
    // cerr << endl;
    // cerr << "t: ";
    // rep(i,n){
    //     cerr << t[i] << " ";
    // }
    // cerr << endl;
    
    // cerr << "b: ";
    // rep(i,n){
    //     cerr << b[i] << " ";
    // }
    // cerr << endl;
    return b;
}

vector<int> f[1000000];


bool ok(vector<int>&a){
    int ma = -1;
    for(auto x:a) ma = max(ma,x);
    set<int> st;
    for(auto x:a)st.insert(x);
    for(int i=0;i<=ma;i++){
        if(st.count(i)==0)return false;
    }
    return true;
}
// void precalc(int n){
//     vector<int> a(n),t(n);
//     if(n==1){
//         rep(i,12){
//             t[0] = i;
//             // f[hsh(a,t)] = func(a,t);
//         }
//     }else if(n==2){
//         rep(i,2){
//             a[0] = i;
//             rep(j,2){
//                 a[1] = j;
//                 if(ok(a)){
//                     rep(ss,12){
//                         t[0] = ss;
//                         rep(tt,12){
//                             t[1] = tt;
//                             f[hsh(a,t)] = func(a,t);
//                         }
//                     }
//                 }
//             }
//         }
//     }else{
//         rep(i,3){
//             a[0] = i;
//             rep(j,3){
//                 a[1] = j;
//                 rep(k,3){
//                     a[2] = k;
//                     if(ok(a)){
//                         rep(ss,12){
//                             t[0] = ss;
//                             rep(tt,12){
//                                 t[1] = tt;
//                                 rep(uu,12){
//                                     t[2] = uu;
//                                     f[hsh(a,t)] = func(a,t);
//                                 }
//                             }
//                         }
//                     }
//                 }
//             }
//         }
//     }
// }



vector<int> calc(vector<int>&a,vector<int>&t,bool first,bool last){
    int n = a.size();
    vector<int> b = t;
    if(first){
        rep(i,n){
            if(b[i]==2)b[i] = 10;
            if(b[i]==4)b[i] = 7;
            if(b[i]==5)b[i] = 9;
            if(b[i]==8)b[i] = 11;
        }
    }
    if(last){
        rep(i,n){
            if(b[i]==10)b[i] = 11;
            if(b[i]==2)b[i] = 8;
            if(b[i]==3)b[i] = 7;
            if(b[i]==6)b[i] = 9;
        }
    }
    return func(a,b);
    //return f[hsh(b,t)];
}

bool include_zero(vector<int>&a){
    rep(i,a.size()){
        if(a[i]==0)return true;
    }
    return false;
}

void dfs(vector<int>&a,vector<int>&t,vector<int>&p,int id,int sz,int n,ll val,bool first,bool last,map<pair<vector<int>,vector<int> >,ll>& nxt){
    if(sz==n){
        vector<int> fff = calc(a,p,first,last);
        // cerr << "a: ";
        // rep(i,n){
        //     cerr << a[i] << " ";
        // }
        // cerr << endl;
        // cerr << "p: ";
        // rep(i,n){
        //     cerr << p[i] << " ";
        // }
        // cerr << endl;
        
        // cerr << "f: ";
        // rep(i,n){
        //     cerr << fff[i] << " ";
        // }
        // cerr << endl;
        // vector<int> ggg= func(a,p);
        
        // cerr << "g: ";
        // rep(i,n){
        //     cerr << ggg[i] << " ";
        // }
        // cerr << endl;
        if(include_zero(fff)){
            nxt[make_pair(fff,t)] += val;
        }
        return;
    }
    if(id==12)return;
    for(int i=0;i<=min(t[id],1);i++){
        int s = sz + i;
        t[id] -= i;
        for(int j=0;j<i;j++){
            p.push_back(id);
        }
        if(i==0){
            dfs(a,t,p,id+1,s,n,val,first,last,nxt);    
        }else{
            dfs(a,t,p,0,s,n,val,first,last,nxt);
        }
        t[id] += i;
        for(int j=0;j<i;j++){
            p.pop_back();   
        }
    }
}


int main(){
    int n,m;
    cin >> n >> m;
    vector<int>t(12);
    rep(i,12){
        cin >> t[i];
    }
    if(n<m){
        swap(n,m);
        trans(t);
    }
    // precalc(m);
    map<pair<vector<int>,vector<int>>,ll> mp;
    vector<int> aa(m);
    rep(i,m){
        aa[i] = i;
    }
    mp[make_pair(aa,t)] = 1;
    rep(i,n){
        map<pair<vector<int>,vector<int> >,ll> nxt;
        for(auto &x:mp){
            auto aa = x.first.first;
            auto tt = x.first.second;
            vector<int> t;
            dfs(aa,tt,t,0,0,m,x.second,i==0,i==(n-1),nxt);
        }
        swap(mp,nxt);
        // cerr << i << endl;
        // for(auto& x:mp){
        //     cerr << "a: ";
        //     for(auto &y:x.first.first){
        //         cerr << y << " ";
        //     }
        //     cerr << endl;
        //     cerr << "t: ";
        //     for(auto &y:x.first.second){
        //         cerr << y << " ";
        //     }
        //     cerr <<": " << x.second << endl;
        // }
    }
    ll res = 0;
    for(auto &x:mp){
        if(x.first.first[m-1]==0){
            res += x.second;
        }
    }
    cout << res << endl;
    return 0;
}
accuracy: 1
time_ms: 2670
memory_kb: 32444
final_rank: 8

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 12

enum DIR{
	N,
	E,
	S,
	W,
};

enum Type{
	Plane,
	N_S,
	W_E,
	N_E,
	S_E,
	W_S,
	W_N,
	W_Plane,
	N_Plane,
	E_Plane,
	S_Plane,
	Cross,
};


int R,C;
int input[SIZE];
int POW[16];
int num_tile;
ll dp[8][1024*32][11];
vector<int> BIT[1024*32][12];
bool table[SIZE][4];
Type type[15],type_array[SIZE] = {Plane,N_S,W_E,N_E,S_E,W_S,W_N,W_Plane,N_Plane,E_Plane,S_Plane,Cross};



//あるタイルについては、その割り当てビットが左にあるものから使う
int calc_next_state(int rest_state,int USE[3]){

	int index[SIZE] = {0};

	int ret = rest_state;

	for(int i = 0; i < R; i++){
		ret -= POW[BIT[rest_state][USE[i]][index[USE[i]]++]];
	}

	return ret;
}

/*
 * 接続状態
 *
 * 行数1: (0:左端と連結)/(1:左端と非連結)
 * 行数2: (0:全て左上と連結)/(1:行0のみが左上と連結)/(2:行1のみが左上と連結)/(3:全て左上と非連結)
 * 行数3: (0:全て左上と連結)/(1:行0,1が左上と連結)/(2:行0,2が左上と連結)/(3:行1,2が左上と連結)
 *        (4:行0のみが左上と連結,行1,2が連結)/(5:行1のみが左上と連結,行0,2が連結)/(6:行2のみが左上と連結,行0,1が連結)
 * 	      (7:行0のみが左上と連結,行1,2が非連結)/(8:行1のみが左上と連結,行0,2が非連結)/(9:行2のみが左上と連結,行0,1が非連結)
 *        (10:全て左上と非連結)
 *
 * */


ll recursive(int col,int pre_E_state,int rest_state,int pre_con_state){

	if(col == C){

		switch(R){
		case 1:
			if(pre_con_state == 0){

				return 1;

			}else{

				return 0;
			}

			break;
		case 2:
			if(pre_con_state == 0 || pre_con_state == 2){

				return 1;
			}else{

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 0 || pre_con_state == 2 || pre_con_state == 3 || pre_con_state == 6 ||
					pre_con_state == 9){

				return 1;
			}else{

				return 0;
			}
			break;
		}
	}

	if(dp[pre_E_state][rest_state][pre_con_state] != -1){

		return dp[pre_E_state][rest_state][pre_con_state];
	}

	//左上と連結しているタイルが1毎もないなら打ち切り
	if(col >= 1){

		if(pre_E_state == 0){

			return 0;
		}

		switch(R){
		case 1:
			if(pre_con_state == 1){

				return 0;
			}
			break;
		case 2:
			if(pre_con_state == 3){

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 10){

				return 0;
			}
			break;
		}
	}

	ll ret = 0;

	int pre[3],now[3],T[3];

	switch(R){
	case 1:

		switch(pre_con_state){
		case 0:

			pre[0] = 1; //1:左上と同じグループ
			break;
		case 1:

			pre[0] = 2;
			break;
		}
		break;

	case 2:

		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 2;
			break;
		case 2:
			pre[0] = 2;
			pre[1] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 2;
			break;
		}
		break;

	case 3:
		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 2:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 4:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 2;
			break;
		case 5:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 6:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 7:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 3;
			break;
		case 8:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 3;
			break;
		case 9:
			pre[0] = 2;
			pre[1] = 3;
			pre[2] = 1;
			break;
		case 10:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 2;
			break;
		}
		break;
	}

	//どのタイルが何枚残っているのかを計算
	int work[SIZE] = {0};

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			work[type[loop]]++;
		}
	}

	vector<int> V;
	for(int i = 0; i < SIZE; i++){
		if(work[i] > 0){
			V.push_back(i);
		}
	}

	int USE[3] = {0};
	int next_E_state,next_con_state,next_rest_state;


	switch(R){
	case 1: //1枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			USE[0] = a;

			next_rest_state = calc_next_state(rest_state,USE);

			if(col == 0){

				if(a == Plane){

					next_con_state = 1;

				}else{

					next_con_state = 0;
				}

			}else{

				if(pre[0] == 1 && table[a][W]){

					next_con_state = 0;

				}else{

					next_con_state = 1;
				}
			}

			ret += recursive(col+1,table[a][E],next_rest_state,next_con_state);
		}

		break;
	case 2: //2枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			USE[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;
				USE[1] = b;


				next_rest_state = calc_next_state(rest_state,USE);
				next_E_state = 0;
				for(int i = 0; i < 2; i++){
					if(table[T[i]][E]){

						next_E_state += POW[i];
					}
				}

				if(col == 0){

					//行0
					if(T[0] == Plane){

						now[0] = 2;

					}else{

						now[0] = 1;
					}

					//行1
					if(table[T[0]][S] && table[T[1]][N]){

						now[1] = now[0];

					}else{

						now[1] = now[0]+1;
					}

				}else{ //col >= 1

					//まずは左→右の遷移を見る
					for(int i = 0; i < 2; i++){

						//左のセルが右に接続可で、T[i]が左に接続可
						if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

							now[i] = pre[i];

						}else{

							now[i] = i+3;
						}
					}

					//上→下の遷移を見る
					if(now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

						if(now[0] == 1){

							now[1] = 1;

						}else if(now[1] == 1){

							now[0] = 1;

						}else{

							now[0] = 2;
							now[1] = 2;
						}
					}
				}

				//next_con_state
				if(now[0] == now[1]){

					if(now[0] == 1){

						next_con_state = 0;

					}else{

						next_con_state = 3;
					}

				}else{ //now[0] != now[1]

					if(now[0] == 1){

						next_con_state = 1;
					}else if(now[1] == 1){

						next_con_state = 2;

					}else{

						next_con_state = 3;
					}
				}

				ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
			}
		}

		break;
	case 3: //3枚選ぶ

		for(int a = 0; a < V.size(); a++){
			T[0] = V[a];
			USE[0] = V[a];
			for(int b = 0; b < V.size(); b++){
				if(a == b && work[V[a]] <= 1)continue;
				T[1] = V[b];
				USE[1] = V[b];
				for(int c = 0; c < V.size(); c++){
					if(work[V[c]] == 0)continue;
					if(a == c && work[V[a]] <= 1)continue;
					if(b == c && work[V[b]] <= 1)continue;
					if(a == c && b == c && work[V[a]] <= 2)continue;
					T[2] = V[c];
					USE[2] = V[c];

					next_rest_state = calc_next_state(rest_state,USE);
					next_E_state = 0;

					for(int i = 0; i < 3; i++){
						if(table[T[i]][E]){

							next_E_state += POW[i];
						}
					}

					if(col == 0){

						if(T[0] == Plane){

							now[0] = 2;

						}else{

							now[0] = 1;
						}
						if(table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];

						}else{

							now[1] = now[0]+1;
						}
						if(table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}else{

							now[2] = now[1]+1;
						}

					}else{ //col >= 1

						//まずは左→右の遷移を見る
						for(int i = 0; i < 3; i++){

							//左のセルが1で右に接続可で、T[i]が左に接続可
							if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

								now[i] = pre[i];

							}else{

								now[i] = i+4;
							}
						}

						//1のセルがあったら優先して処理

						//上→下へ
						if(now[0] == 1 && now[1] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[2] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[2] = 1;
						}
						//下→上へ
						if(now[2] == 1 && now[1] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[0] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[0] = 1;
						}

						//己型
						if(now[1] == 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = 1;
						}
						//逆己型
						if(now[1] == 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[0] = 1;
						}

						//1以外の更新
						if(now[0] != 1 && now[1] != 1 && now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];
						}
						if(now[1] != 1 && now[2] != 1 && now[1] != now[2] && table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}
						//己型
						if(now[1] != 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = now[1];
						}
						//逆己型
						if(now[1] != 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[1] = now[0];
						}
					}

					if(now[0] == now[1] && now[0] == now[2]){ //3つ同じ

						if(now[0] == 1){

							next_con_state = 0;

						}else{

							next_con_state = 10;
						}

					}else if(now[0] == now[1]){

						if(now[0] == 1){

							next_con_state = 1;

						}else{

							if(now[2] == 1){

								next_con_state = 6;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[0] == now[2]){

						if(now[0] == 1){

							next_con_state = 2;

						}else{

							if(now[1] == 1){

								next_con_state = 5;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[1] == now[2]){

						if(now[1] == 1){

							next_con_state = 3;

						}else{

							if(now[0] == 1){

								next_con_state = 4;

							}else{

								next_con_state = 10;
							}
						}


					}else{ //全部違う

						if(now[0] == 1){

							next_con_state = 7;

						}else if(now[1] == 1){

							next_con_state = 8;

						}else if(now[2] == 1){

							next_con_state = 9;

						}else{

							next_con_state = 10;
						}
					}

					ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
				}
			}
		}

		break;
	}

	return dp[pre_E_state][rest_state][pre_con_state] = ret;
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	//Plane
	table[Plane][N] = false,table[Plane][E] = false,table[Plane][S] = false,table[Plane][W] = false;
	//sigle load
	table[N_S][N] = true,table[N_S][E] = false,table[N_S][S] = true,table[N_S][W] = false;
	table[W_E][N] = false,table[W_E][E] = true,table[W_E][S] = false,table[W_E][W] = true;
	table[N_E][N] = true,table[N_E][E] = true,table[N_E][S] = false,table[N_E][W] = false;
	table[S_E][N] = false,table[S_E][E] = true,table[S_E][S] = true,table[S_E][W] = false;
	table[W_S][N] = false,table[W_S][E] = false,table[W_S][S] = true,table[W_S][W] = true;
	table[W_N][N] = true,table[W_N][E] = false,table[W_N][S] = false,table[W_N][W] = true;
	//three-forked-load
	table[W_Plane][N] = true,table[W_Plane][E] = true,table[W_Plane][S] = true,table[W_Plane][W] = false;
	table[N_Plane][N] = false,table[N_Plane][E] = true,table[N_Plane][S] = true,table[N_Plane][W] = true;
	table[E_Plane][N] = true,table[E_Plane][E] = false,table[E_Plane][S] = true,table[E_Plane][W] = true;
	table[S_Plane][N] = true,table[S_Plane][E] = true,table[S_Plane][S] = false,table[S_Plane][W] = true;
	//Cross
	table[Cross][N] = true,table[Cross][E] = true,table[Cross][S] = true,table[Cross][W] = true;


	scanf("%d %d",&R,&C);
	for(int i = 0; i < SIZE; i++){

		scanf("%d",&input[i]);
	}

	if(R > C){

		/*
		 * 行と列を交換→右に90度倒して、左右を反転させる
		 * */

		swap(R,C);
		swap(input[W_E],input[N_S]);
		swap(input[N_E],input[W_S]);
		swap(input[S_Plane],input[E_Plane]);
		swap(input[N_Plane],input[W_Plane]);
	}

	//ビットの各桁に各タイルを割り当てる
	num_tile = 0;
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < input[i]; k++){

			type[num_tile] = type_array[i];
			num_tile++;
		}
	}

	if(num_tile < R*C){

		printf("0\n");
		return 0;
	}

	for(int i = 0; i < POW[R]; i++){
		for(int k = 0; k < POW[num_tile]; k++){
			for(int a = 0; a < 11; a++){

				dp[i][k][a] = -1;
			}
		}
	}

	//ビットが立っている場所を前計算
	for(int state = 0; state < POW[num_tile]; state++){
		for(int loop = 0; loop < num_tile; loop++){
			if(state & POW[loop]){
				BIT[state][type[loop]].push_back(loop);
			}
		}
	}

	int first_pre;
	switch(R){
	case 1:
		first_pre = 1;
		break;
	case 2:
		first_pre = 3;
		break;
	case 3:
		first_pre = 10;
		break;
	}

	printf("%lld\n",recursive(0,0,POW[num_tile]-1,first_pre));

	return 0;
}
accuracy: 1
time_ms: 1400
memory_kb: 41884
final_rank: 5

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 12

enum DIR{
	N,
	E,
	S,
	W,
};

enum Type{
	Plane,
	N_S,
	W_E,
	N_E,
	S_E,
	W_S,
	W_N,
	W_Plane,
	N_Plane,
	E_Plane,
	S_Plane,
	Cross,
};


int R,C;
int input[SIZE];
int POW[16];
int num_tile;
ll dp[8][1024*32][11];
vector<int> BIT[1024*32][12];
bool table[SIZE][4];
Type type[15],type_array[SIZE] = {Plane,N_S,W_E,N_E,S_E,W_S,W_N,W_Plane,N_Plane,E_Plane,S_Plane,Cross};



//あるタイルについては、その割り当てビットが左にあるものから使う
int calc_next_state(int rest_state,int USE[3]){

	int index[SIZE] = {0};

	int ret = rest_state;

	for(int i = 0; i < R; i++){
		ret -= POW[BIT[rest_state][USE[i]][index[USE[i]]++]];
	}

	return ret;
}

/*
 * 接続状態
 *
 * 行数1: (0:左端と連結)/(1:左端と非連結)
 * 行数2: (0:全て左上と連結)/(1:行0のみが左上と連結)/(2:行1のみが左上と連結)/(3:全て左上と非連結)
 * 行数3: (0:全て左上と連結)/(1:行0,1が左上と連結)/(2:行0,2が左上と連結)/(3:行1,2が左上と連結)
 *        (4:行0のみが左上と連結,行1,2が連結)/(5:行1のみが左上と連結,行0,2が連結)/(6:行2のみが左上と連結,行0,1が連結)
 * 	      (7:行0のみが左上と連結,行1,2が非連結)/(8:行1のみが左上と連結,行0,2が非連結)/(9:行2のみが左上と連結,行0,1が非連結)
 *        (10:全て左上と非連結)
 *
 * */


ll recursive(int col,int pre_E_state,int rest_state,int pre_con_state){

	//printf("col:%d pre_E_state:%d rest_state:%d pre_con_state:%d\n",col,pre_E_state,rest_state,pre_con_state);

	if(col == C){

		//printf("列:%d rest_state:%d\n",C,rest_state);

		switch(R){
		case 1:
			if(pre_con_state == 0){

				return 1;

			}else{

				return 0;
			}

			break;
		case 2:
			if(pre_con_state == 0 || pre_con_state == 2){

				return 1;
			}else{

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 0 || pre_con_state == 2 || pre_con_state == 3 || pre_con_state == 6 ||
					pre_con_state == 9){

				return 1;
			}else{

				return 0;
			}
			break;
		}
	}

	if(dp[pre_E_state][rest_state][pre_con_state] != -1){

		return dp[pre_E_state][rest_state][pre_con_state];
	}

	//左上と連結しているタイルが1毎もないなら打ち切り
	if(col >= 1){

		if(pre_E_state == 0){

			return 0;
		}

		switch(R){
		case 1:
			if(pre_con_state == 1){

				return 0;
			}
			break;
		case 2:
			if(pre_con_state == 3){

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 10){

				return 0;
			}
			break;
		}
	}

	ll ret = 0;

	int pre[3],now[3],T[3];

	switch(R){
	case 1:

		switch(pre_con_state){
		case 0:

			pre[0] = 1; //1:左上と同じグループ
			break;
		case 1:

			pre[0] = 2;
			break;
		}
		break;

	case 2:

		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 2;
			break;
		case 2:
			pre[0] = 2;
			pre[1] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 2;
			break;
		}
		break;

	case 3:
		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 2:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 4:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 2;
			break;
		case 5:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 6:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 7:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 3;
			break;
		case 8:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 3;
			break;
		case 9:
			pre[0] = 2;
			pre[1] = 3;
			pre[2] = 1;
			break;
		case 10:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 2;
			break;
		}
		break;
	}

	//どのタイルが何枚残っているのかを計算
	int work[SIZE] = {0};

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			work[type[loop]]++;
		}
	}

	vector<int> V;
	for(int i = 0; i < SIZE; i++){
		if(work[i] > 0){
			V.push_back(i);
		}
	}

	int USE[3] = {0};
	int next_E_state,next_con_state,next_rest_state;

	/*for(int i = 0; i < SIZE; i++){

		printf("work[%d]:%d\n",i,work[i]);
	}

	*/


	switch(R){
	case 1: //1枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			USE[0] = a;

			next_rest_state = calc_next_state(rest_state,USE);

			if(col == 0){

				if(a == Plane){

					next_con_state = 1;

				}else{

					next_con_state = 0;
				}

			}else{

				if(pre[0] == 1 && table[a][W]){

					next_con_state = 0;

				}else{

					next_con_state = 1;
				}
			}

			ret += recursive(col+1,table[a][E],next_rest_state,next_con_state);
		}

		break;
	case 2: //2枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			USE[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;
				USE[1] = b;


				next_rest_state = calc_next_state(rest_state,USE);
				next_E_state = 0;
				for(int i = 0; i < 2; i++){
					if(table[T[i]][E]){

						next_E_state += POW[i];
					}
				}

				if(col == 0){

					//行0
					if(T[0] == Plane){

						now[0] = 2;

					}else{

						now[0] = 1;
					}

					//行1
					if(table[T[0]][S] && table[T[1]][N]){

						now[1] = now[0];

					}else{

						now[1] = now[0]+1;
					}

				}else{ //col >= 1

					//まずは左→右の遷移を見る
					for(int i = 0; i < 2; i++){

						//左のセルが右に接続可で、T[i]が左に接続可
						if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

							now[i] = pre[i];

						}else{

							now[i] = i+3;
						}
					}

					//上→下の遷移を見る
					if(now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

						if(now[0] == 1){

							now[1] = 1;

						}else if(now[1] == 1){

							now[0] = 1;

						}else{

							now[0] = 2;
							now[1] = 2;
						}
					}
				}

				//next_con_state
				if(now[0] == now[1]){

					if(now[0] == 1){

						next_con_state = 0;

					}else{

						next_con_state = 3;
					}

				}else{ //now[0] != now[1]

					if(now[0] == 1){

						next_con_state = 1;
					}else if(now[1] == 1){

						next_con_state = 2;

					}else{

						next_con_state = 3;
					}
				}

				ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
			}
		}

		break;
	case 3: //3枚選ぶ

		for(int a = 0; a < V.size(); a++){
			T[0] = V[a];
			USE[0] = V[a];
			for(int b = 0; b < V.size(); b++){
				if(a == b && work[V[a]] <= 1)continue;
				T[1] = V[b];
				USE[1] = V[b];
				for(int c = 0; c < V.size(); c++){
					if(work[V[c]] == 0)continue;
					if(a == c && work[V[a]] <= 1)continue;
					if(b == c && work[V[b]] <= 1)continue;
					if(a == c && b == c && work[V[a]] <= 2)continue;
					T[2] = V[c];
					USE[2] = V[c];

					next_rest_state = calc_next_state(rest_state,USE);
					next_E_state = 0;

					for(int i = 0; i < 3; i++){
						if(table[T[i]][E]){

							next_E_state += POW[i];
						}
					}

					if(col == 0){

						if(T[0] == Plane){

							now[0] = 2;

						}else{

							now[0] = 1;
						}
						if(table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];

						}else{

							now[1] = now[0]+1;
						}
						if(table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}else{

							now[2] = now[1]+1;
						}

					}else{ //col >= 1

						//まずは左→右の遷移を見る
						for(int i = 0; i < 3; i++){

							//左のセルが1で右に接続可で、T[i]が左に接続可
							if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

								now[i] = pre[i];

							}else{

								now[i] = i+4;
							}
						}


						//1のセルがあったら優先して処理

						//上→下へ
						if(now[0] == 1 && now[1] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[2] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[2] = 1;
						}
						//下→上へ
						if(now[2] == 1 && now[1] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[0] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[0] = 1;
						}

						//己型
						if(now[1] == 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = 1;
						}
						//逆己型
						if(now[1] == 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[0] = 1;
						}

						//1以外の更新
						if(now[0] != 1 && now[1] != 1 && now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];
						}
						if(now[1] != 1 && now[2] != 1 && now[1] != now[2] && table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}
						//己型
						if(now[1] != 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = now[1];
						}
						//逆己型
						if(now[1] != 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[1] = now[0];
						}
					}

					if(now[0] == now[1] && now[0] == now[2]){ //3つ同じ

						if(now[0] == 1){

							next_con_state = 0;

						}else{

							next_con_state = 10;
						}

					}else if(now[0] == now[1]){

						if(now[0] == 1){

							next_con_state = 1;

						}else{

							if(now[2] == 1){

								next_con_state = 6;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[0] == now[2]){

						if(now[0] == 1){

							next_con_state = 2;

						}else{

							if(now[1] == 1){

								next_con_state = 5;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[1] == now[2]){

						if(now[1] == 1){

							next_con_state = 3;

						}else{

							if(now[0] == 1){

								next_con_state = 4;

							}else{

								next_con_state = 10;
							}
						}


					}else{ //全部違う

						if(now[0] == 1){

							next_con_state = 7;

						}else if(now[1] == 1){

							next_con_state = 8;

						}else if(now[2] == 1){

							next_con_state = 9;

						}else{

							next_con_state = 10;
						}
					}

					ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
				}
			}
		}

		break;
	}

	return dp[pre_E_state][rest_state][pre_con_state] = ret;
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	//Plane
	table[Plane][N] = false,table[Plane][E] = false,table[Plane][S] = false,table[Plane][W] = false;
	//sigle load
	table[N_S][N] = true,table[N_S][E] = false,table[N_S][S] = true,table[N_S][W] = false;
	table[W_E][N] = false,table[W_E][E] = true,table[W_E][S] = false,table[W_E][W] = true;
	table[N_E][N] = true,table[N_E][E] = true,table[N_E][S] = false,table[N_E][W] = false;
	table[S_E][N] = false,table[S_E][E] = true,table[S_E][S] = true,table[S_E][W] = false;
	table[W_S][N] = false,table[W_S][E] = false,table[W_S][S] = true,table[W_S][W] = true;
	table[W_N][N] = true,table[W_N][E] = false,table[W_N][S] = false,table[W_N][W] = true;
	//three-forked-load
	table[W_Plane][N] = true,table[W_Plane][E] = true,table[W_Plane][S] = true,table[W_Plane][W] = false;
	table[N_Plane][N] = false,table[N_Plane][E] = true,table[N_Plane][S] = true,table[N_Plane][W] = true;
	table[E_Plane][N] = true,table[E_Plane][E] = false,table[E_Plane][S] = true,table[E_Plane][W] = true;
	table[S_Plane][N] = true,table[S_Plane][E] = true,table[S_Plane][S] = false,table[S_Plane][W] = true;
	//Cross
	table[Cross][N] = true,table[Cross][E] = true,table[Cross][S] = true,table[Cross][W] = true;


	scanf("%d %d",&R,&C);
	for(int i = 0; i < SIZE; i++){

		scanf("%d",&input[i]);
	}

	if(R > C){

		/*
		 * 行と列を交換→右に90度倒して、左右を反転させる
		 * */

		swap(R,C);
		swap(input[W_E],input[N_S]);
		swap(input[N_E],input[W_S]);
		swap(input[S_Plane],input[E_Plane]);
		swap(input[N_Plane],input[W_Plane]);
	}

	//ビットの各桁に各タイルを割り当てる
	num_tile = 0;
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < input[i]; k++){

			type[num_tile] = type_array[i];
			num_tile++;
		}
	}

	/*printf("num_tile:%d\n",num_tile);
	for(int i = 0; i < num_tile; i++){

		printf("type[%d]:%d\n",i,type[i]);
	}*/

	if(num_tile < R*C){

		printf("0\n");
		return 0;
	}

	for(int i = 0; i < POW[R]; i++){
		for(int k = 0; k < POW[num_tile]; k++){
			for(int a = 0; a < 11; a++){

				dp[i][k][a] = -1;
			}
		}
	}

	//ビットが立っている場所を前計算
	for(int state = 0; state < POW[num_tile]; state++){
		for(int loop = 0; loop < num_tile; loop++){
			if(state & POW[loop]){
				BIT[state][type[loop]].push_back(loop);
			}
		}
	}

	int first_pre;
	switch(R){
	case 1:
		first_pre = 1;
		break;
	case 2:
		first_pre = 3;
		break;
	case 3:
		first_pre = 10;
		break;
	}

	printf("%lld\n",recursive(0,0,POW[num_tile]-1,first_pre));

	return 0;
}
accuracy: 1
time_ms: 1410
memory_kb: 41916
final_rank: 6

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 12

enum DIR{
	N,
	E,
	S,
	W,
};

enum Type{
	Plane,
	N_S,
	W_E,
	N_E,
	S_E,
	W_S,
	W_N,
	W_Plane,
	N_Plane,
	E_Plane,
	S_Plane,
	Cross,
};


int R,C;
int input[SIZE];
int POW[16];
int num_tile;
ll dp[8][1024*32][11];
bool table[SIZE][4];
map<string,int> MAP[1024*32];
Type type[15],type_array[SIZE] = {Plane,N_S,W_E,N_E,S_E,W_S,W_N,W_Plane,N_Plane,E_Plane,S_Plane,Cross};



//あるタイルについては、その割り当てビットが左にあるものから使う
int calc_next_state(int rest_state,int USE[3]){

	queue<int> Q[SIZE];

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			Q[type[loop]].push(loop); //bitをpush
		}
	}

	int ret = rest_state;

	for(int i = 0; i < R; i++){
		ret -= POW[Q[USE[i]].front()];
		Q[USE[i]].pop();
	}

	return ret;
}

/*
 * 接続状態
 *
 * 行数1: (0:左端と連結)/(1:左端と非連結)
 * 行数2: (0:全て左上と連結)/(1:行0のみが左上と連結)/(2:行1のみが左上と連結)/(3:全て左上と非連結)
 * 行数3: (0:全て左上と連結)/(1:行0,1が左上と連結)/(2:行0,2が左上と連結)/(3:行1,2が左上と連結)
 *        (4:行0のみが左上と連結,行1,2が連結)/(5:行1のみが左上と連結,行0,2が連結)/(6:行2のみが左上と連結,行0,1が連結)
 * 	      (7:行0のみが左上と連結,行1,2が非連結)/(8:行1のみが左上と連結,行0,2が非連結)/(9:行2のみが左上と連結,行0,1が非連結)
 *        (10:全て左上と非連結)
 *
 * */


ll recursive(int col,int pre_E_state,int rest_state,int pre_con_state){

	//printf("col:%d pre_E_state:%d rest_state:%d pre_con_state:%d\n",col,pre_E_state,rest_state,pre_con_state);

	if(col == C){

		//printf("列:%d rest_state:%d\n",C,rest_state);

		switch(R){
		case 1:
			if(pre_con_state == 0){

				return 1;

			}else{

				return 0;
			}

			break;
		case 2:
			if(pre_con_state == 0 || pre_con_state == 2){

				return 1;
			}else{

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 0 || pre_con_state == 2 || pre_con_state == 3 || pre_con_state == 6 ||
					pre_con_state == 9){

				return 1;
			}else{

				return 0;
			}
			break;
		}
	}

	if(dp[pre_E_state][rest_state][pre_con_state] != -1){

		return dp[pre_E_state][rest_state][pre_con_state];
	}

	//左上と連結しているタイルが1毎もないなら打ち切り
	if(col >= 1){

		if(pre_E_state == 0){

			return 0;
		}

		switch(R){
		case 1:
			if(pre_con_state == 1){

				return 0;
			}
			break;
		case 2:
			if(pre_con_state == 3){

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 10){

				return 0;
			}
			break;
		}
	}

	ll ret = 0;

	int pre[3],now[3],T[3];

	switch(R){
	case 1:

		switch(pre_con_state){
		case 0:

			pre[0] = 1; //1:左上と同じグループ
			break;
		case 1:

			pre[0] = 2;
			break;
		}
		break;

	case 2:

		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 2;
			break;
		case 2:
			pre[0] = 2;
			pre[1] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 2;
			break;
		}
		break;

	case 3:
		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 2:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 4:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 2;
			break;
		case 5:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 6:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 7:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 3;
			break;
		case 8:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 3;
			break;
		case 9:
			pre[0] = 2;
			pre[1] = 3;
			pre[2] = 1;
			break;
		case 10:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 2;
			break;
		}
		break;
	}

	//どのタイルが何枚残っているのかを計算
	int work[SIZE] = {0};

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			work[type[loop]]++;
		}
	}

	vector<int> V;
	for(int i = 0; i < SIZE; i++){
		if(work[i] > 0){
			V.push_back(i);
		}
	}

	int USE[3] = {0};
	int next_E_state,next_con_state,next_rest_state;

	/*for(int i = 0; i < SIZE; i++){

		printf("work[%d]:%d\n",i,work[i]);
	}

	*/


	switch(R){
	case 1: //1枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			USE[0] = 1;

			next_rest_state = calc_next_state(rest_state,USE);

			if(col == 0){

				if(a == Plane){

					next_con_state = 1;

				}else{

					next_con_state = 0;
				}

			}else{

				if(pre[0] == 1 && table[a][W]){

					next_con_state = 0;

				}else{

					next_con_state = 1;
				}
			}

			ret += recursive(col+1,table[a][E],next_rest_state,next_con_state);

			USE[a] = 0;
		}

		break;
	case 2: //2枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			USE[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;
				USE[1] = b;


				next_rest_state = calc_next_state(rest_state,USE);
				next_E_state = 0;
				for(int i = 0; i < 2; i++){
					if(table[T[i]][E]){

						next_E_state += POW[i];
					}
				}

				if(col == 0){

					//行0
					if(T[0] == Plane){

						now[0] = 2;

					}else{

						now[0] = 1;
					}

					//行1
					if(table[T[0]][S] && table[T[1]][N]){

						now[1] = now[0];

					}else{

						now[1] = now[0]+1;
					}

				}else{ //col >= 1

					//まずは左→右の遷移を見る
					for(int i = 0; i < 2; i++){

						//左のセルが右に接続可で、T[i]が左に接続可
						if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

							now[i] = pre[i];

						}else{

							now[i] = i+3;
						}
					}

					//上→下の遷移を見る
					if(now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

						if(now[0] == 1){

							now[1] = 1;

						}else if(now[1] == 1){

							now[0] = 1;

						}else{

							now[0] = 2;
							now[1] = 2;
						}
					}
				}

				//next_con_state
				if(now[0] == now[1]){

					if(now[0] == 1){

						next_con_state = 0;

					}else{

						next_con_state = 3;
					}

				}else{ //now[0] != now[1]

					if(now[0] == 1){

						next_con_state = 1;
					}else if(now[1] == 1){

						next_con_state = 2;

					}else{

						next_con_state = 3;
					}
				}

				ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
			}
		}

		break;
	case 3: //3枚選ぶ

		for(int a = 0; a < V.size(); a++){
			T[0] = V[a];
			USE[0] = V[a];
			for(int b = 0; b < V.size(); b++){
				if(a == b && work[V[a]] <= 1)continue;
				T[1] = V[b];
				USE[1] = V[b];
				for(int c = 0; c < V.size(); c++){
					if(work[V[c]] == 0)continue;
					if(a == c && work[V[a]] <= 1)continue;
					if(b == c && work[V[b]] <= 1)continue;
					if(a == c && b == c && work[V[a]] <= 2)continue;
					T[2] = V[c];
					USE[2] = V[c];

					next_rest_state = calc_next_state(rest_state,USE);
					next_E_state = 0;

					for(int i = 0; i < 3; i++){
						if(table[T[i]][E]){

							next_E_state += POW[i];
						}
					}

					if(col == 0){

						if(T[0] == Plane){

							now[0] = 2;

						}else{

							now[0] = 1;
						}
						if(table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];

						}else{

							now[1] = now[0]+1;
						}
						if(table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}else{

							now[2] = now[1]+1;
						}

					}else{ //col >= 1

						//まずは左→右の遷移を見る
						for(int i = 0; i < 3; i++){

							//左のセルが1で右に接続可で、T[i]が左に接続可
							if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

								now[i] = pre[i];

							}else{

								now[i] = i+4;
							}
						}


						//1のセルがあったら優先して処理

						//上→下へ
						if(now[0] == 1 && now[1] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[2] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[2] = 1;
						}
						//下→上へ
						if(now[2] == 1 && now[1] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[0] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[0] = 1;
						}

						//己型
						if(now[1] == 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = 1;
						}
						//逆己型
						if(now[1] == 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[0] = 1;
						}

						//1以外の更新
						if(now[0] != 1 && now[1] != 1 && now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];
						}
						if(now[1] != 1 && now[2] != 1 && now[1] != now[2] && table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}
						//己型
						if(now[1] != 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = now[1];
						}
						//逆己型
						if(now[1] != 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[1] = now[0];
						}
					}

					if(now[0] == now[1] && now[0] == now[2]){ //3つ同じ

						if(now[0] == 1){

							next_con_state = 0;

						}else{

							next_con_state = 10;
						}

					}else if(now[0] == now[1]){

						if(now[0] == 1){

							next_con_state = 1;

						}else{

							if(now[2] == 1){

								next_con_state = 6;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[0] == now[2]){

						if(now[0] == 1){

							next_con_state = 2;

						}else{

							if(now[1] == 1){

								next_con_state = 5;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[1] == now[2]){

						if(now[1] == 1){

							next_con_state = 3;

						}else{

							if(now[0] == 1){

								next_con_state = 4;

							}else{

								next_con_state = 10;
							}
						}


					}else{ //全部違う

						if(now[0] == 1){

							next_con_state = 7;

						}else if(now[1] == 1){

							next_con_state = 8;

						}else if(now[2] == 1){

							next_con_state = 9;

						}else{

							next_con_state = 10;
						}
					}

					ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
				}
			}
		}

		break;
	}

	return dp[pre_E_state][rest_state][pre_con_state] = ret;
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	//Plane
	table[Plane][N] = false,table[Plane][E] = false,table[Plane][S] = false,table[Plane][W] = false;
	//sigle load
	table[N_S][N] = true,table[N_S][E] = false,table[N_S][S] = true,table[N_S][W] = false;
	table[W_E][N] = false,table[W_E][E] = true,table[W_E][S] = false,table[W_E][W] = true;
	table[N_E][N] = true,table[N_E][E] = true,table[N_E][S] = false,table[N_E][W] = false;
	table[S_E][N] = false,table[S_E][E] = true,table[S_E][S] = true,table[S_E][W] = false;
	table[W_S][N] = false,table[W_S][E] = false,table[W_S][S] = true,table[W_S][W] = true;
	table[W_N][N] = true,table[W_N][E] = false,table[W_N][S] = false,table[W_N][W] = true;
	//three-forked-load
	table[W_Plane][N] = true,table[W_Plane][E] = true,table[W_Plane][S] = true,table[W_Plane][W] = false;
	table[N_Plane][N] = false,table[N_Plane][E] = true,table[N_Plane][S] = true,table[N_Plane][W] = true;
	table[E_Plane][N] = true,table[E_Plane][E] = false,table[E_Plane][S] = true,table[E_Plane][W] = true;
	table[S_Plane][N] = true,table[S_Plane][E] = true,table[S_Plane][S] = false,table[S_Plane][W] = true;
	//Cross
	table[Cross][N] = true,table[Cross][E] = true,table[Cross][S] = true,table[Cross][W] = true;


	scanf("%d %d",&R,&C);
	for(int i = 0; i < SIZE; i++){

		scanf("%d",&input[i]);
	}

	if(R > C){

		/*
		 * 行と列を交換→右に90度倒して、左右を反転させる
		 * */

		swap(R,C);
		swap(input[W_E],input[N_S]);
		swap(input[N_E],input[W_S]);
		swap(input[S_Plane],input[E_Plane]);
		swap(input[N_Plane],input[W_Plane]);
	}

	//ビットの各桁に各タイルを割り当てる
	num_tile = 0;
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < input[i]; k++){

			type[num_tile] = type_array[i];
			num_tile++;
		}
	}

	/*printf("num_tile:%d\n",num_tile);
	for(int i = 0; i < num_tile; i++){

		printf("type[%d]:%d\n",i,type[i]);
	}*/

	if(num_tile < R*C){

		printf("0\n");
		return 0;
	}

	for(int i = 0; i < POW[R]; i++){
		for(int k = 0; k < POW[num_tile]; k++){
			for(int a = 0; a < 11; a++){

				dp[i][k][a] = -1;

			}
		}
	}

	int first_pre;
	switch(R){
	case 1:
		first_pre = 1;
		break;
	case 2:
		first_pre = 3;
		break;
	case 3:
		first_pre = 10;
		break;
	}

	printf("%lld\n",recursive(0,0,POW[num_tile]-1,first_pre));

	return 0;
}
accuracy: 0.08620689655172414
time_ms: 30
memory_kb: 5408
final_rank: 11

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 12

enum DIR{
	N,
	E,
	S,
	W,
};

enum Type{
	Plane,
	N_S,
	W_E,
	N_E,
	S_E,
	W_S,
	W_N,
	W_Plane,
	N_Plane,
	E_Plane,
	S_Plane,
	Cross,
};


int R,C;
int input[SIZE];
int POW[16];
int num_tile;
ll dp[8][1024*32][11];
bool table[SIZE][4];
map<string,int> MAP[1024*32];
Type type[15],type_array[SIZE] = {Plane,N_S,W_E,N_E,S_E,W_S,W_N,W_Plane,N_Plane,E_Plane,S_Plane,Cross};



//あるタイルについては、その割り当てビットが左にあるものから使う
int calc_next_state(int rest_state,int USE[3]){

	queue<int> Q[SIZE];

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			Q[type[loop]].push(loop); //bitをpush
		}
	}

	int ret = rest_state;

	for(int i = 0; i < R; i++){
		ret -= POW[Q[USE[i]].front()];
		Q[USE[i]].pop();
	}

	return ret;
}

/*
 * 接続状態
 *
 * 行数1: (0:左端と連結)/(1:左端と非連結)
 * 行数2: (0:全て左上と連結)/(1:行0のみが左上と連結)/(2:行1のみが左上と連結)/(3:全て左上と非連結)
 * 行数3: (0:全て左上と連結)/(1:行0,1が左上と連結)/(2:行0,2が左上と連結)/(3:行1,2が左上と連結)
 *        (4:行0のみが左上と連結,行1,2が連結)/(5:行1のみが左上と連結,行0,2が連結)/(6:行2のみが左上と連結,行0,1が連結)
 * 	      (7:行0のみが左上と連結,行1,2が非連結)/(8:行1のみが左上と連結,行0,2が非連結)/(9:行2のみが左上と連結,行0,1が非連結)
 *        (10:全て左上と非連結)
 *
 * */


ll recursive(int col,int pre_E_state,int rest_state,int pre_con_state){

	//printf("col:%d pre_E_state:%d rest_state:%d pre_con_state:%d\n",col,pre_E_state,rest_state,pre_con_state);

	if(col == C){

		//printf("列:%d rest_state:%d\n",C,rest_state);

		switch(R){
		case 1:
			if(pre_con_state == 0){

				return 1;

			}else{

				return 0;
			}

			break;
		case 2:
			if(pre_con_state == 0 || pre_con_state == 2){

				return 1;
			}else{

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 0 || pre_con_state == 2 || pre_con_state == 3 || pre_con_state == 6 ||
					pre_con_state == 9){

				return 1;
			}else{

				return 0;
			}
			break;
		}
	}

	if(dp[pre_E_state][rest_state][pre_con_state] != -1){

		return dp[pre_E_state][rest_state][pre_con_state];
	}

	//左上と連結しているタイルが1毎もないなら打ち切り
	if(col >= 1){

		if(pre_E_state == 0){

			return 0;
		}

		switch(R){
		case 1:
			if(pre_con_state == 1){

				return 0;
			}
			break;
		case 2:
			if(pre_con_state == 3){

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 10){

				return 0;
			}
			break;
		}
	}

	ll ret = 0;

	int pre[3],now[3],T[3];

	switch(R){
	case 1:

		switch(pre_con_state){
		case 0:

			pre[0] = 1; //1:左上と同じグループ
			break;
		case 1:

			pre[0] = 2;
			break;
		}
		break;

	case 2:

		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 2;
			break;
		case 2:
			pre[0] = 2;
			pre[1] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 2;
			break;
		}
		break;

	case 3:
		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 2:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 4:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 2;
			break;
		case 5:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 6:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 7:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 3;
			break;
		case 8:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 3;
			break;
		case 9:
			pre[0] = 2;
			pre[1] = 3;
			pre[2] = 1;
			break;
		case 10:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 2;
			break;
		}
		break;
	}

	//どのタイルが何枚残っているのかを計算
	int work[SIZE] = {0};

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			work[type[loop]]++;
		}
	}

	vector<int> V;
	for(int i = 0; i < SIZE; i++){
		if(work[i] > 0){
			V.push_back(i);
		}
	}

	int USE[3] = {0};
	int next_E_state,next_con_state,next_rest_state;

	/*for(int i = 0; i < SIZE; i++){

		printf("work[%d]:%d\n",i,work[i]);
	}

	*/


	switch(R){
	case 1: //1枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			USE[a] = 1;

			next_rest_state = calc_next_state(rest_state,USE);

			if(col == 0){

				if(a == Plane){

					next_con_state = 1;

				}else{

					next_con_state = 0;
				}

			}else{

				if(pre[0] == 1 && table[a][W]){

					next_con_state = 0;

				}else{

					next_con_state = 1;
				}
			}

			ret += recursive(col+1,table[a][E],next_rest_state,next_con_state);

			USE[a] = 0;
		}

		break;
	case 2: //2枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			USE[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;
				USE[1] = b;


				next_rest_state = calc_next_state(rest_state,USE);
				next_E_state = 0;
				for(int i = 0; i < 2; i++){
					if(table[T[i]][E]){

						next_E_state += POW[i];
					}
				}

				if(col == 0){

					//行0
					if(T[0] == Plane){

						now[0] = 2;

					}else{

						now[0] = 1;
					}

					//行1
					if(table[T[0]][S] && table[T[1]][N]){

						now[1] = now[0];

					}else{

						now[1] = now[0]+1;
					}

				}else{ //col >= 1

					//まずは左→右の遷移を見る
					for(int i = 0; i < 2; i++){

						//左のセルが右に接続可で、T[i]が左に接続可
						if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

							now[i] = pre[i];

						}else{

							now[i] = i+3;
						}
					}

					//上→下の遷移を見る
					if(now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

						if(now[0] == 1){

							now[1] = 1;

						}else if(now[1] == 1){

							now[0] = 1;

						}else{

							now[0] = 2;
							now[1] = 2;
						}
					}
				}

				//next_con_state
				if(now[0] == now[1]){

					if(now[0] == 1){

						next_con_state = 0;

					}else{

						next_con_state = 3;
					}

				}else{ //now[0] != now[1]

					if(now[0] == 1){

						next_con_state = 1;
					}else if(now[1] == 1){

						next_con_state = 2;

					}else{

						next_con_state = 3;
					}
				}

				ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
			}
		}

		break;
	case 3: //3枚選ぶ

		for(int a = 0; a < V.size(); a++){
			T[0] = V[a];
			USE[0] = V[a];
			for(int b = 0; b < V.size(); b++){
				if(a == b && work[V[a]] <= 1)continue;
				T[1] = V[b];
				USE[1] = V[b];
				for(int c = 0; c < V.size(); c++){
					if(work[V[c]] == 0)continue;
					if(a == c && work[V[a]] <= 1)continue;
					if(b == c && work[V[b]] <= 1)continue;
					if(a == c && b == c && work[V[a]] <= 2)continue;
					T[2] = V[c];
					USE[2] = V[c];

					next_rest_state = calc_next_state(rest_state,USE);
					next_E_state = 0;

					for(int i = 0; i < 3; i++){
						if(table[T[i]][E]){

							next_E_state += POW[i];
						}
					}

					if(col == 0){

						if(T[0] == Plane){

							now[0] = 2;

						}else{

							now[0] = 1;
						}
						if(table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];

						}else{

							now[1] = now[0]+1;
						}
						if(table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}else{

							now[2] = now[1]+1;
						}

					}else{ //col >= 1

						//まずは左→右の遷移を見る
						for(int i = 0; i < 3; i++){

							//左のセルが1で右に接続可で、T[i]が左に接続可
							if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

								now[i] = pre[i];

							}else{

								now[i] = i+4;
							}
						}


						//1のセルがあったら優先して処理

						//上→下へ
						if(now[0] == 1 && now[1] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[2] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[2] = 1;
						}
						//下→上へ
						if(now[2] == 1 && now[1] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[0] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[0] = 1;
						}

						//己型
						if(now[1] == 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = 1;
						}
						//逆己型
						if(now[1] == 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[0] = 1;
						}

						//1以外の更新
						if(now[0] != 1 && now[1] != 1 && now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];
						}
						if(now[1] != 1 && now[2] != 1 && now[1] != now[2] && table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}
						//己型
						if(now[1] != 1 && now[2] != 1 && pre[1] == pre[2] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] && ((pre_E_state & POW[2]) > 0)	&& table[T[2]][W]){

							now[2] = now[1];
						}
						//逆己型
						if(now[1] != 1 && now[0] != 1 && pre[1] == pre[0] && ((pre_E_state & POW[1]) > 0) &&
								table[T[1]][W] &&  ((pre_E_state & POW[0]) > 0)	&& table[T[0]][W]){

							now[1] = now[0];
						}
					}

					if(now[0] == now[1] && now[0] == now[2]){ //3つ同じ

						if(now[0] == 1){

							next_con_state = 0;

						}else{

							next_con_state = 10;
						}

					}else if(now[0] == now[1]){

						if(now[0] == 1){

							next_con_state = 1;

						}else{

							if(now[2] == 1){

								next_con_state = 6;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[0] == now[2]){

						if(now[0] == 1){

							next_con_state = 2;

						}else{

							if(now[1] == 1){

								next_con_state = 5;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[1] == now[2]){

						if(now[1] == 1){

							next_con_state = 3;

						}else{

							if(now[0] == 1){

								next_con_state = 4;

							}else{

								next_con_state = 10;
							}
						}


					}else{ //全部違う

						if(now[0] == 1){

							next_con_state = 7;

						}else if(now[1] == 1){

							next_con_state = 8;

						}else if(now[2] == 1){

							next_con_state = 9;

						}else{

							next_con_state = 10;
						}
					}

					ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);
				}
			}
		}

		break;
	}

	return dp[pre_E_state][rest_state][pre_con_state] = ret;
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	//Plane
	table[Plane][N] = false,table[Plane][E] = false,table[Plane][S] = false,table[Plane][W] = false;
	//sigle load
	table[N_S][N] = true,table[N_S][E] = false,table[N_S][S] = true,table[N_S][W] = false;
	table[W_E][N] = false,table[W_E][E] = true,table[W_E][S] = false,table[W_E][W] = true;
	table[N_E][N] = true,table[N_E][E] = true,table[N_E][S] = false,table[N_E][W] = false;
	table[S_E][N] = false,table[S_E][E] = true,table[S_E][S] = true,table[S_E][W] = false;
	table[W_S][N] = false,table[W_S][E] = false,table[W_S][S] = true,table[W_S][W] = true;
	table[W_N][N] = true,table[W_N][E] = false,table[W_N][S] = false,table[W_N][W] = true;
	//three-forked-load
	table[W_Plane][N] = true,table[W_Plane][E] = true,table[W_Plane][S] = true,table[W_Plane][W] = false;
	table[N_Plane][N] = false,table[N_Plane][E] = true,table[N_Plane][S] = true,table[N_Plane][W] = true;
	table[E_Plane][N] = true,table[E_Plane][E] = false,table[E_Plane][S] = true,table[E_Plane][W] = true;
	table[S_Plane][N] = true,table[S_Plane][E] = true,table[S_Plane][S] = false,table[S_Plane][W] = true;
	//Cross
	table[Cross][N] = true,table[Cross][E] = true,table[Cross][S] = true,table[Cross][W] = true;


	scanf("%d %d",&R,&C);
	for(int i = 0; i < SIZE; i++){

		scanf("%d",&input[i]);
	}

	if(R > C){

		/*
		 * 行と列を交換→右に90度倒して、左右を反転させる
		 * */

		swap(R,C);
		swap(input[W_E],input[N_S]);
		swap(input[N_E],input[W_S]);
		swap(input[S_Plane],input[E_Plane]);
		swap(input[N_Plane],input[W_Plane]);
	}

	//ビットの各桁に各タイルを割り当てる
	num_tile = 0;
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < input[i]; k++){

			type[num_tile] = type_array[i];
			num_tile++;
		}
	}

	/*printf("num_tile:%d\n",num_tile);
	for(int i = 0; i < num_tile; i++){

		printf("type[%d]:%d\n",i,type[i]);
	}*/

	if(num_tile < R*C){

		printf("0\n");
		return 0;
	}

	for(int i = 0; i < POW[R]; i++){
		for(int k = 0; k < POW[num_tile]; k++){
			for(int a = 0; a < 11; a++){

				dp[i][k][a] = -1;

			}
		}
	}

	int first_pre;
	switch(R){
	case 1:
		first_pre = 1;
		break;
	case 2:
		first_pre = 3;
		break;
	case 3:
		first_pre = 10;
		break;
	}

	printf("%lld\n",recursive(0,0,POW[num_tile]-1,first_pre));

	return 0;
}
accuracy: 0.08620689655172414
time_ms: 20
memory_kb: 5440
final_rank: 10

code_snippet: #include<bits/stdc++.h>
typedef long long int ll;
typedef unsigned long long int ull;
#define BIG_NUM 2000000000
#define HUGE_NUM 99999999999999999
#define MOD 1000000007
#define EPS 0.000000001
using namespace std;


#define SIZE 12

enum DIR{
	N,
	E,
	S,
	W,
};

enum Type{
	Plane,
	N_S,
	W_E,
	N_E,
	S_E,
	W_S,
	W_N,
	W_Plane,
	N_Plane,
	E_Plane,
	S_Plane,
	Cross,
};


int R,C;
int input[SIZE];
int POW[16];
int num_tile;
ll dp[8][1024*32][11];
bool table[SIZE][4];
Type type[15],type_array[SIZE] = {Plane,N_S,W_E,N_E,S_E,W_S,W_N,W_Plane,N_Plane,E_Plane,S_Plane,Cross};



//あるタイルについては、その割り当てビットが左にあるものから使う
int calc_next_state(int rest_state,int USE[SIZE]){

	bool check[SIZE];
	queue<int> Q[SIZE];

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			check[loop] = true;
			Q[type[loop]].push(loop); //bitをpush

		}else{

			check[loop] = false;
		}
	}

	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < USE[i]; k++){
			check[Q[i].front()] = false;
			Q[i].pop();
		}
	}

	int ret = 0;

	for(int i = 0; i < num_tile; i++){
		if(check[i]){

			ret += POW[i];
		}
	}

	return ret;
}

/*
 * 接続状態
 *
 * 行数1: (0:左端と連結)/(1:左端と非連結)
 * 行数2: (0:全て左上と連結)/(1:行0のみが左上と連結)/(2:行1のみが左上と連結)/(3:全て左上と非連結)
 * 行数3: (0:全て左上と連結)/(1:行0,1が左上と連結)/(2:行0,2が左上と連結)/(3:行1,2が左上と連結)
 *        (4:行0のみが左上と連結,行1,2が連結)/(5:行1のみが左上と連結,行0,2が連結)/(6:行2のみが左上と連結,行0,1が連結)
 * 	      (7:行0のみが左上と連結,行1,2が非連結)/(8:行1のみが左上と連結,行0,2が非連結)/(9:行2のみが左上と連結,行0,1が非連結)
 *        (10:全て左上と非連結)
 *
 * */


ll recursive(int col,int pre_E_state,int rest_state,int pre_con_state){

	if(col == C){

		switch(R){
		case 1:
			if(pre_con_state == 0){

				return 1;

			}else{

				return 0;
			}

			break;
		case 2:
			if(pre_con_state == 0 || pre_con_state == 2){

				return 1;
			}else{

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 0 || pre_con_state == 2 || pre_con_state == 3 || pre_con_state == 6 ||
					pre_con_state == 9){

				return 1;
			}else{

				return 0;
			}
			break;
		}
	}

	if(dp[pre_E_state][rest_state][pre_con_state] != -1){

		return dp[pre_E_state][rest_state][pre_con_state];
	}

	//左上と連結しているタイルが1毎もないなら打ち切り
	if(col >= 1){

		switch(R){
		case 1:
			if(pre_con_state == 1){

				return 0;
			}
			break;
		case 2:
			if(pre_con_state == 3){

				return 0;
			}
			break;
		case 3:
			if(pre_con_state == 10){

				return 0;
			}
			break;
		}
	}

	ll ret = 0;

	int pre[3],now[3],T[3];

	switch(R){
	case 1:

		switch(pre_con_state){
		case 0:

			pre[0] = 1; //1:左上と同じグループ
			break;
		case 1:

			pre[0] = 2;
			break;
		}
		break;

	case 2:

		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 2;
			break;
		case 2:
			pre[0] = 2;
			pre[1] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 2;
			break;
		}
		break;

	case 3:
		switch(pre_con_state){
		case 0:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 1:
			pre[0] = 1;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 2:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 3:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 1;
			break;
		case 4:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 2;
			break;
		case 5:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 2;
			break;
		case 6:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 1;
			break;
		case 7:
			pre[0] = 1;
			pre[1] = 2;
			pre[2] = 3;
			break;
		case 8:
			pre[0] = 2;
			pre[1] = 1;
			pre[2] = 3;
			break;
		case 9:
			pre[0] = 2;
			pre[1] = 3;
			pre[2] = 1;
			break;
		case 10:
			pre[0] = 2;
			pre[1] = 2;
			pre[2] = 2;
			break;
		}
		break;
	}

	//どのタイルが何枚残っているのかを計算
	int work[SIZE] = {0};

	for(int loop = 0; loop < num_tile; loop++){
		if(rest_state & POW[loop]){

			work[type[loop]]++;
		}
	}

	int USE[SIZE] = {0};
	int next_E_state,next_con_state,next_rest_state;


	switch(R){
	case 1: //1枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			USE[a] = 1;

			next_rest_state = calc_next_state(rest_state,USE);

			if(col == 0){

				if(a == Plane){

					next_con_state = 1;

				}else{

					next_con_state = 0;
				}

			}else{

				if(pre[0] == 1 && table[a][W]){

					next_con_state = 0;

				}else{

					next_con_state = 1;
				}
			}

			ret += recursive(col+1,table[a][E],next_rest_state,next_con_state);

			USE[a] = 0;
		}

		break;
	case 2: //2枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;

				USE[a]++;
				USE[b]++;

				next_rest_state = calc_next_state(rest_state,USE);
				next_E_state = 0;
				for(int i = 0; i < 2; i++){
					if(table[T[i]][E]){

						next_E_state += POW[i];
					}
				}

				if(col == 0){

					//行0
					if(T[0] == Plane){

						now[0] = 2;

					}else{

						now[0] = 1;
					}

					//行1
					if(table[T[0]][S] && table[T[1]][N]){

						now[1] = now[0];

					}else{

						now[1] = now[0]+1;
					}

				}else{ //col >= 1

					//まずは左→右の遷移を見る
					for(int i = 0; i < 2; i++){

						//左のセルが右に接続可で、T[i]が左に接続可
						if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

							now[i] = pre[i];

						}else{

							now[i] = i+3;
						}
					}

					//上→下の遷移を見る
					if(now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

						if(now[0] == 1){

							now[1] = 1;

						}else if(now[1] == 1){

							now[0] = 1;

						}else{

							now[0] = 2;
							now[1] = 2;
						}
					}
				}

				//next_con_state
				if(now[0] == now[1]){

					if(now[0] == 1){

						next_con_state = 0;

					}else{

						next_con_state = 3;
					}

				}else{ //now[0] != now[1]

					if(now[0] == 1){

						next_con_state = 1;
					}else if(now[1] == 1){

						next_con_state = 2;

					}else{

						next_con_state = 3;
					}
				}

				ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);

				USE[a]--;
				USE[b]--;
			}
		}

		break;
	case 3: //3枚選ぶ

		for(int a = 0; a < SIZE; a++){
			if(work[a] == 0)continue;
			T[0] = a;
			for(int b = 0; b < SIZE; b++){
				if(work[b] == 0)continue;
				if(a == b && work[a] <= 1)continue;
				T[1] = b;
				for(int c = 0; c < SIZE; c++){
					if(work[c] == 0)continue;
					if(a == c && work[a] <= 1)continue;
					if(b == c && work[b] <= 1)continue;
					if(a == c && b == c && work[a] <= 2)continue;
					T[2] = c;

					USE[a]++;
					USE[b]++;
					USE[c]++;

					next_rest_state = calc_next_state(rest_state,USE);
					next_E_state = 0;

					for(int i = 0; i < 3; i++){
						if(table[T[i]][E]){

							next_E_state += POW[i];
						}
					}

					if(col == 0){

						if(T[0] == Plane){

							now[0] = 2;

						}else{

							now[0] = 1;
						}
						if(table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];

						}else{

							now[1] = now[0]+1;
						}
						if(table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}else{

							now[2] = now[1]+1;
						}

					}else{ //col >= 1

						//まずは左→右の遷移を見る
						for(int i = 0; i < 3; i++){

							//左のセルが1で右に接続可で、T[i]が左に接続可
							if(((pre_E_state & POW[i]) != 0) && table[T[i]][W]){

								now[i] = pre[i];

							}else{

								now[i] = i+4;
							}
						}


						//1のセルがあったら優先して処理

						//上→下へ
						if(now[0] == 1 && now[1] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[2] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[2] = 1;
						}
						//下→上へ
						if(now[2] == 1 && now[1] != 1 && table[T[1]][S] && table[T[2]][N]){

							now[1] = 1;
						}
						if(now[1] == 1 && now[0] != 1 && table[T[0]][S] && table[T[1]][N]){

							now[0] = 1;
						}

						//1以外の更新
						if(now[0] != 1 && now[1] != 1 && now[0] != now[1] && table[T[0]][S] && table[T[1]][N]){

							now[1] = now[0];
						}
						if(now[1] != 1 && now[2] != 1 && now[1] != now[2] && table[T[1]][S] && table[T[2]][N]){

							now[2] = now[1];
						}
					}

					if(now[0] == now[1] && now[0] == now[2]){ //3つ同じ

						if(now[0] == 1){

							next_con_state = 0;

						}else{

							next_con_state = 10;
						}

					}else if(now[0] == now[1]){

						if(now[0] == 1){

							next_con_state = 1;

						}else{

							if(now[2] == 1){

								next_con_state = 6;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[0] == now[2]){

						if(now[0] == 1){

							next_con_state = 2;

						}else{

							if(now[1] == 1){

								next_con_state = 5;

							}else{

								next_con_state = 10;
							}
						}

					}else if(now[1] == now[2]){

						if(now[1] == 1){

							next_con_state = 3;

						}else{

							if(now[0] == 1){

								next_con_state = 4;

							}else{

								next_con_state = 10;
							}
						}


					}else{ //全部違う

						if(now[0] == 1){

							next_con_state = 7;

						}else if(now[1] == 1){

							next_con_state = 8;

						}else if(now[2] == 1){

							next_con_state = 9;

						}else{

							next_con_state = 10;
						}
					}

					ret += recursive(col+1,next_E_state,next_rest_state,next_con_state);

					USE[a]--;
					USE[b]--;
					USE[c]--;
				}
			}
		}

		break;
	}

	return dp[pre_E_state][rest_state][pre_con_state] = ret;
}

int main(){

	POW[0] = 1;
	for(int i = 1; i <= 15; i++){

		POW[i] = POW[i-1]*2;
	}

	//Plane
	table[Plane][N] = false,table[Plane][E] = false,table[Plane][S] = false,table[Plane][W] = false;
	//sigle load
	table[N_S][N] = true,table[N_S][E] = false,table[N_S][S] = true,table[N_S][W] = false;
	table[W_E][N] = false,table[W_E][E] = true,table[W_E][S] = false,table[W_E][W] = true;
	table[N_E][N] = true,table[N_E][E] = true,table[N_E][S] = false,table[N_E][W] = false;
	table[S_E][N] = false,table[S_E][E] = true,table[S_E][S] = true,table[S_E][W] = false;
	table[W_S][N] = false,table[W_S][E] = false,table[W_S][S] = true,table[W_S][W] = true;
	table[W_N][N] = true,table[W_N][E] = false,table[W_N][S] = false,table[W_N][W] = true;
	//three-forked-load
	table[W_Plane][N] = true,table[W_Plane][E] = true,table[W_Plane][S] = true,table[W_Plane][W] = false;
	table[N_Plane][N] = false,table[N_Plane][E] = true,table[N_Plane][S] = true,table[N_Plane][W] = true;
	table[E_Plane][N] = true,table[E_Plane][E] = false,table[E_Plane][S] = true,table[E_Plane][W] = true;
	table[S_Plane][N] = true,table[S_Plane][E] = true,table[S_Plane][S] = false,table[S_Plane][W] = true;
	//Cross
	table[Cross][N] = true,table[Cross][E] = true,table[Cross][S] = true,table[Cross][W] = true;


	scanf("%d %d",&R,&C);
	for(int i = 0; i < SIZE; i++){

		scanf("%d",&input[i]);
	}

	if(R > C){

		/*
		 * 行と列を交換→右に90度倒して、左右を反転させる
		 * */

		swap(R,C);
		swap(input[W_E],input[N_S]);
		swap(input[N_E],input[W_S]);
		swap(input[S_Plane],input[E_Plane]);
		swap(input[N_Plane],input[W_Plane]);
	}

	//ビットの各桁に各タイルを割り当てる
	num_tile = 0;
	for(int i = 0; i < SIZE; i++){
		for(int k = 0; k < input[i]; k++){

			type[num_tile] = type_array[i];
			num_tile++;
		}
	}

	if(num_tile < R*C){

		printf("0\n");
		return 0;
	}

	for(int i = 0; i < POW[R]; i++){
		for(int k = 0; k < POW[num_tile]; k++){
			for(int a = 0; a < 11; a++){

				dp[i][k][a] = -1;

			}
		}
	}

	int first_pre;
	switch(R){
	case 1:
		first_pre = 1;
		break;
	case 2:
		first_pre = 3;
		break;
	case 3:
		first_pre = 10;
		break;
	}

	printf("%lld\n",recursive(0,0,POW[num_tile]-1,first_pre));

	return 0;
}
accuracy: 0.39655172413793105
time_ms: 600
memory_kb: 25736
final_rank: 9

code_snippet: #include <iostream>
#include <iomanip>
#include <sstream>
#include <cstdio>
#include <string>
#include <vector>
#include <algorithm>
#include <complex>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <cassert>
#include <climits>
#include <queue>
#include <set>
#include <map>
#include <valarray>
#include <bitset>
#include <stack>
using namespace std;

#define REP(i,n) for(int i=0;i<(int)(n);++i)
#define FOR(i,c) for(__typeof((c).begin())i=(c).begin();i!=(c).end();++i)
#define ALL(c) (c).begin(), (c).end()
typedef long long ll;
typedef pair<int,int> pii;
const int INF = 1<<29;
const double PI = acos(-1);
const double EPS = 1e-8;

bool table[12][4] = {
  0,0,0,0,
    1,0,1,0,
    0,1,0,1,
    1,1,0,0,
    0,1,1,0,
    0,0,1,1,
    1,0,0,1,
    1,1,1,0,
    0,1,1,1,
    1,0,1,1,
    1,1,0,1,
    1,1,1,1
    };
bool connect[12][12][4];

void init() {
  REP(i,12) {
    REP(j,12) {
      REP(k,4) {
        connect[i][j][k] = table[i][k] && table[j][(k+2)%4];
      }
    }
  }
}

int enc[15][1<<15];

void init2(int R, int C, int N) {
  int num = 0;
  REP(i,C) {
    int perm[N];
    REP(j,N) {
      if (j<N-R*i) perm[j] = 0;
      else perm[j] = 1;
    }
    do {
      int S = 0;
      REP(j,N) if (perm[j]) S |= 1<<j;
      enc[i][S] = num++;
    } while(next_permutation(perm,perm+N));
  }
}

// S:始点との接続状態
// T:セル同士の接続状態
// 流れるなら流れた状態にする
void func(int &S, int &T) {
  bool f = 0;
  REP(i,3) if ((T>>i&1) && (S>>i&1)) f = 1;
  if (f) REP(i,3) if (T>>i&1) S |= 1<<i;
}

int encode(int S, int T) {
  if (S==0) return 0;
  if (S==1 && T==6) return 7;
  if (S==2 && T==5) return 8;
  if (S==4 && T==3) return 9;
  return S-1;
}

// pii decode(int x) {
//   if (x==7) return pii(1,6);
//   if (x==8) return pii(2,5);
//   if (x==9) return pii(4,3);
//   return pii(x+1,0);
// }

ll memo[40000][10][1<<3];
int R, C;
int N;

int pnum[12];
int pkind[15];
int pmp[12][15];

ll solve(int x, int U, int S, int T, int Q);

ll dfs(int x, int U, int S, int T, int Q, int NU, int num, int id) {
  if (id == 12) {
    if (num == R) {
      int k = 0;
      int perm[3] = {};
      REP(i,N) {
        if (NU>>i&1) {
          perm[k++] = pkind[i];
        }
      }
      // if (x == 2) {
      //   cout << "x = " << x << endl;
      //   REP(i,num) cout << perm[i] << " "; cout << endl;
      //   cout << bitset<9>(U) <<" " << bitset<3>(S) << " " << bitset<3>(T) << " " << bitset<3>(Q) << endl;
      // }
      ll res = 0;
      do {
        int nS = 0;
        int nT = 0;
        int nQ = 0;
        REP(i,R) {
          if ((Q>>i&1) && table[perm[i]][3]) {
            if (S>>i&1) nS|=1<<i;
            if (T>>i&1) nT |= 1<<i;
          }
          if (table[perm[i]][1]) nQ |= 1<<i;
        }
        //assert(__builtin_popcount(nT) == 0);
        if (__builtin_popcount(nT) == 1) nT = 0;
        if (connect[perm[0]][perm[1]][2]) nT |= 3;
        if (connect[perm[1]][perm[2]][2]) nT |= 6;
        
        if (x == 0) nS |= 1;    // 1列目の1行目は始点
        
        func(nS,nT);
        if (nS) {
          res += solve(x+1, U|NU, nS, nT, nQ);
        }
      } while(next_permutation(perm, perm+R));
      return res;
    } else return 0;
  }
  ll res = 0;
  
  int pct[12] = {};
  REP(i,N) {
    if (U>>i&1) {
      pct[pkind[i]]++;
    }
  }
  REP(i,R-num+1) {
    if (pct[id]+i <= pnum[id]) {
      int UU = NU;
      REP(j,i) UU |= 1<<pmp[id][pct[id]+j];
      res += dfs(x,U,S,T,Q,UU, num+i, id+1);
    } else break;
  }
  return res;
}

ll solve(int x, int U, int S, int T, int Q) {
  if (x == C) {
    // cout << "x = " << x << endl;
    // cout << bitset<9>(U) <<" " << bitset<3>(S) << " " << bitset<3>(T) << " " << bitset<3>(Q) << endl;

    return (S>>(R-1)&1);
  }
  //cout << x << " " << bitset<15>(U) << " "<< enc[x][U] << endl;
  assert(enc[x][U] >= 0);
  int p = encode(S,T);
  ll &r = memo[enc[x][U]][p][Q];
  if (r >= 0) return r;
  
  return r = dfs(x,U,S,T,Q,0,0,0);
}
  
int main() {
  init();
  cin >> R >> C;
  REP(i,12) cin >> pnum[i];
  if (R>C) {
    swap(R,C);
    swap(pnum[1],pnum[2]);
    swap(pnum[3],pnum[5]);
    swap(pnum[7],pnum[8]);
    swap(pnum[9],pnum[10]);
  }
  N = 0;
  REP(i,12) {
    REP(j,pnum[i]) {
      pkind[N] = i;
      pmp[i][j] = N;
      N++;
    }
  }
  // assert(R<=3);
  // assert(N<=15);
  memset(enc,-1,sizeof(enc));
  init2(R,C,N);
  memset(memo,-1,sizeof(memo));
  cout << solve(0,0,0,0,0) << endl;
}
accuracy: 1
time_ms: 2670
memory_kb: 28132
final_rank: 7

code_snippet: #include <iostream>
#include <vector>
#include <cstring>

using namespace std;

// 各パーツの連結情報を表すテーブル
int con[12][4] = {
	{0, 0, 0, 0},
	{0, 1, 0, 1},
	{1, 0, 1, 0},
	{1, 1, 0, 0},
	{1, 0, 0, 1},
	{0, 0, 1, 1},
	{0, 1, 1, 0},
	{1, 1, 0, 1},
	{1, 0, 1, 1},
	{0, 1, 1, 1},
	{1, 1, 1, 0},
	{1, 1, 1, 1}
};

// (R > C)の場合に各パーツを転置して(R < C)に変換するためのテーブル
int chg[] = {0, 2, 1, 5, 4, 3, 6, 8, 7, 10, 9, 11};

// 1列分の連結状況の更新用テーブル(R=3専用)
// 0bit : 置いたピースと1つ前のピースが連結
// 1bit : 置いたピースと1列前(3つ前)のピースが連結
int next[10][4] = {
	{-1, -1, 4, 6}, // 0: 3つ前だけ(1,1)と連結
	    //   x  0:   x   1:   b  2:   x  3:   o
		// o ?     x x      o b     o o     o o
		// x       x        x       x       x
	{-1, -1, 5, 9}, // 1: 3つ前だけ(1,1)と連結 + 1つ前と2つ前が連結 
	    //   b  0:   b   1:   b  2:   b  3:   o
		// o ?     o x      o b     o o     o o
		// b       b        b       b       o
	{0, 1, 0, 1}, // 2: 2つ前だけ(1,1)と連結
		//   x  0:   x   1:   b  2:   x  3:   b
		// x ?     x x      x b     b b     b b
		// o       o        o       o       o
	{0, 1, 1, 1}, // 3: 2つ前だけ(1,1)と連結 + 1つ前と3つ前が連結
		//   b  0:   b   1:   b  2:   b  3:   b
		// b ?     b x      b b     b b     b b
		// o       o        o       o       o
	{2, 6, 2, 6}, // 4: 1つ前だけ(1,1)と連結
		//   o  0:   o   1:   o  2:   o  3:   o
		// x ?     x x      x o     b b     o o
		// x       x        x       x       x
	{2, 6, 3, 9}, // 5: 1つ前だけ(1,1)と連結 + 2つ前と3つ前が連結
		//   o  0:   o   1:   o  2:   o  3:   o
		// b ?     b x      b o     b b     o o
		// b       b        b       b       o
	{8, 9, 8, 9}, // 6: 1つ前と2つ前が(1,1)と連結
		//   o  0:   o   1:   o  2:   o  3:   o
		// x ?     x x      x o     b b     o o
		// o       o        o       o       o
	{2, 6, 6, 6}, // 7: 1つ前と3つ前が(1,1)と連結
		//   o  0:   o   1:   o  2:   o  3:   o
		// o ?     o x      o o     o o     o o
		// x       x        x       x       x
	{0, 1, 7, 9}, // 8: 2つ前と3つ前が(1,1)と連結
		//   x  0:   x   1:   b  2:   x  3:   o
		// o ?     o x      o b     o o     o o
		// o       o        o       o       o
	{8, 9, 9, 9}, // 9: 3つ前まですべて(1,1)と連結
		//   o  0:   o   1:   o  2:   o  3:   o
		// o ?     o x      o o     o o     o o
		// o       o        o       o       o
};

// [使用済みピース] : 最大2^15通り
// [最後に置いたピースから下方向に道が伸びてるか] : 2通り
// [置いた最左列の各ピースから右に道が伸びてるか] : 最大2^min(R,C) = 2^3通り
// [スタート地点のピースからの連結情報] : min(R,C) = 3 の場合で10通り
long long dp[1<<15][2][8][10];

int bitCount(int b){
	int res = 0;
	for(int t=b;t;t&=(t-1)) res++;
	return res;
}

int main(){
	int R, C;
	int visit[12];
	while(cin >> R >> C){
		vector<int> vi;
		for(int i=0;i<12;i++){
			int n; cin >> n;
			for(int j=0;j<n;j++) vi.push_back(i);
		}

		if(R > C){
			// R < C (R ≦ 3) になるようにピースを変換
			swap(R, C);
			for(int i=0;i<vi.size();i++) vi[i] = chg[vi[i]];
		}
		long long res = 0;

		memset(dp, 0, sizeof(dp));
		vector<int> mask(vi.size(), 0);
		for(int i=0;i<vi.size();i++){
			for(int j=0;j<i;j++)
				if(vi[i] == vi[j]) mask[j] |= 1<<i; // 重複カウント排除用マスク
		}
		for(int i=0;i<vi.size();i++){
			if(mask[i] != 0) continue;
			bool downPipe  = (R > 1 && con[vi[i]][3]);
			bool rightPipe = con[vi[i]][0];
			if(!downPipe && !rightPipe) continue;
			dp[1<<i][downPipe][rightPipe][R==3 ? 4 : 1] = 1;
		}
		int type[] = {0, 2, 4, 10}; // type[i] : min(R, C) = i の時の連結情報の種類数
		for(int i=0;i<(1<<vi.size());++i){
			int bits = bitCount(i);
			if(bits >= R*C) continue;
			for(int down=0;down<2;down++){
				for(int right=0;right<(1<<R);right++){
					if(down == 0 && right == 0) continue; // 置いたピースにつなげられる経路がない
					for(int connect=0;connect<type[R];connect++){
						if(dp[i][down][right][connect] == 0) continue; // この状態に至る経路がない
						for(int j=0;j<vi.size();j++){
							if(i&(1<<j)) continue;
							if((i&mask[j]) != mask[j]) continue; // 同じ種類のピースはindexが若いものから使う
							bool ndown = bits%R != R-1 && con[vi[j]][3];
							int nright = (2*right)%(1<<R) + con[vi[j]][0];
							int nconnect;
							if(R < 3){
								nconnect = (2*connect)%(1<<R);
								if((right&(1<<(R-1))) && con[vi[j]][2]){
									if(connect&(1<<(R-1))){
										nconnect |= 1;
										if(down && con[vi[j]][1]) nconnect |= (1<<(R-1));
									}
								}
								if(down && con[vi[j]][1] && (connect&1))
								nconnect |= 1;
								if(nconnect == 0) continue; // 最左ピースがどれもスタート地点のピースと連結でない
								if((nconnect&1) && bits+1 == R*C) // スタート地点のピースとゴール地点のピースが連結
									res += dp[i][down][right][connect]; 
							}
							else if(R == 3){
								int piece = 0;
								if(down && con[vi[j]][1]) piece |= 1;
								if((right&(1<<(R-1))) && con[vi[j]][2]) piece |= 2;
								nconnect = next[connect][piece];
								if(nconnect == -1) continue; // 最左ピースがどれもスタート地点のピースと連結でない
								if((0x000002F0 & (1<<nconnect)) && bits+1 == R*C) // スタート地点のピースとゴール地点のピースが連結
									res += dp[i][down][right][connect];
							}
							dp[i|(1<<j)][ndown][nright][nconnect] += dp[i][down][right][connect];
						}
					}
				}
			}
		}
		cout << res << endl;
	}
}
accuracy: 1
time_ms: 90
memory_kb: 42176
final_rank: 4