Vasily the bear has two favorite integers n and k and a pencil. Besides, he's got k jars with different water color paints. All jars are numbered in some manner from 1 to k, inclusive. The jar number i contains the paint of the i-th color. Initially the bear took a pencil and drew four segments on the coordinate plane. All of them end at point (0, 0). They begin at: (0, 2n), (0,  - 2n), (2n, 0), ( - 2n, 0). Then for each i = 1, 2, ..., n, the bear drew two squares. The first square has the following vertex coordinates: (2i, 0), ( - 2i, 0), (0,  - 2i), (0, 2i). The second square has the following vertex coordinates: ( - 2i - 1,  - 2i - 1), ( - 2i - 1, 2i - 1), (2i - 1,  - 2i - 1), (2i - 1, 2i - 1). After that, the bear drew another square: (1, 0), ( - 1, 0), (0,  - 1), (0, 1). All points mentioned above form the set of points A.The sample of the final picture at n = 0The sample of the final picture at n = 2The bear decided to paint the resulting picture in k moves. The i-th move consists of the following stages:   The bear chooses 3 distinct points in set А so that any pair of the chosen points has a segment on the picture between them. The chosen points and segments mark the area that mustn't contain any previously painted points.  The bear paints the area bounded by the chosen points and segments the i-th color. Note that after the k-th move some parts of the picture can stay unpainted.The bear asked you to calculate, how many distinct ways there are to paint his picture. A way to paint the picture is a sequence of three-element sets of points he chose on each step. Two sequences are considered distinct if there is such number i (1 ≤ i ≤ k), that the i-th members of these sequences do not coincide as sets. As the sought number can be rather large, you only need to calculate the remainder after dividing it by number 1000000007 (109 + 7).

The first line contains two integers n and k, separated by a space (0 ≤ n, k ≤ 200).

Print exactly one integer — the answer to the problem modulo 1000000007 (109 + 7).

/*
 * the general idea is first to calulate dp[i][j][k], which means the ways to choose that there're i triangle have the point of (0, 0),
 * left j simple-triangles, and the left part can form k triangles with two simple-triangles. This part is the hardest, we need to calculate
 * in O((n * 4) ^ 2);
 * then we can use recurrence to calculate the number of the case that there're i triangle have the point of (0, 0), left j simple-triangles,
 * and the left part can form k triangles with two simple-triangles.
 * The left task is much easier.
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <time.h>

using namespace std;

#define mpr make_pair
typedef unsigned long long ull;
typedef long long ll;

//.........................mi.......feng.......xian.......wai.......jin.......zhi.......challenge...............................................

const int maxn = 210;
const ll mod = 1000000007;
int n, col;
ll have[maxn];
int dp[5][maxn * 12][maxn * 4];
ll c[2510][2510];
ll stat1[5][maxn * 4][maxn * 4];
int radd[5][3][maxn * 4][maxn * 4];

int main(){
//	time_t be = clock();
	ios_base::sync_with_stdio(0);
	for(int i = 0; i < 2500; i++) {
		c[i][0] = 1;
		for(int j = 1; j <= i; j++) {
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
			if(c[i][j] > mod) c[i][j] -= mod;
		}
	}

	scanf("%d%d", &n, &col);
	have[0] = 1;
	for(int i = 1; i <= n; i++) have[i] = have[i - 1] + 3;

	// most tough part
	for(int i = 0; i < 5; i++) {
		ll all = col - i;
		if(all < 0) break;
		for(int t = 0; t <= n * 12; t++) dp[i][t][0] = c[t][all];
		for(int j = 1; j <= n * 4; j++) for(int t = 0; t <= n * 12 - j * 2; t++) {
			ll ans1 = (ll)dp[i][t + 2][j - 1] + dp[i][t + 1][j - 1] - dp[i][t][j - 1];
			if(ans1 < 0) ans1 += mod;
			while(ans1 > mod) ans1 -= mod;
			dp[i][t][j] = ans1;
		}
	}

	for(int i = -1; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++){
		int cnt = n * 4; int add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 + j11 + k11;
		pair <int, int> be = mpr(cnt, n * 4 - (max(i11, j11) + max(k11, j11)) - i11 - k11);
		stat1[add][be.first][be.second]++;
		add++;
		stat1[add][be.first][be.second]++;
		radd[add][0][be.first][be.second]++;
		radd[add][0][be.first - min(i11, k11)][be.second]--;
		radd[add][1][be.first - min(i11, k11)][be.second]++;
		radd[add][1][be.first - max(i11, k11)][be.second - abs(i11 - k11)]--;
		radd[add][2][be.first - max(i11, k11)][be.second - abs(i11 - k11)]++;
		radd[add][2][be.first - n][be.second - abs(i11 - k11) - 2 * (n - max(i11, k11))]--;
	}
	for(int i = 0; i <= 4; i++) for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) {
		for(int t = 0; t < 3; t++) {
			radd[i][t][j][k] += radd[i][t][j + 1][k + t], stat1[i][j][k] += radd[i][t][j + 1][k + t];
			if(radd[i][t][j][k] > mod) radd[i][t][j][k] -= mod;
			if(stat1[i][j][k] > mod) stat1[i][j][k] -= mod;
		}
	}
	for(int i = 0; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++) {
		int cnt = n * 4; ll add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 * 2 + j11 + k11;
		stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] += 4;
		if(stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] > mod)
			stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] -= mod;
	}
	if(col >= 2) for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) {
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] += 2;
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] %= mod;
	}
	ll ans = 0;

	for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) for(int t = 0; t < 5; t++) if(stat1[t][k][j] && t <= col){
		ans += dp[t][k * 3 - j * 2][j] * stat1[t][k][j] % mod;
		if(ans > mod) ans -= mod;
	}

	for(ll i = 1; i <= col; i++) ans = ans * i % mod;
	cout << ans << endl;

	return 0;
}

/*
 * temp.cpp
 *
 *  Created on: 2012-7-18
 *      Author: BSBandme
 */
//#pragma comment(linker, "/STACK:1024000000,1024000000")
#include <iostream>
#include <fstream>
#include <string.h>
#include <cstdio>
#include <algorithm>
#include <string>
#include <vector>
#include <queue>
#include <cassert>
#include <list>
#include <iomanip>
#include <math.h>
#include <deque>
#include <utility>
#include <map>
#include <set>
#include <bitset>
#include <numeric>
#include <climits>
#include <cctype>
#include <cmath>
#include <cstdlib>
#include <sstream>
#include <time.h>

using namespace std;

#define mpr make_pair
typedef unsigned long long ull;
typedef long long ll;
typedef pair <int, int> pii;
typedef pair <ll, ll> pll;
typedef pair <double, double> pdd;
typedef vector <int> vi;
typedef vector <ll> vll;
typedef vector <double> vd;
typedef vector <string> vs;
typedef map <string, int> mpsi;
typedef map <double, int> mpdi;
typedef map <int, int> mpii;

const double pi = acos(0.0) * 2.0;
const double eps = 1e-12;
const int step[8][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, {1, 1}, {1, -1}, {-1, 1}, {-1, -1}};

template <class T> inline T abs1(T a) {return a < 0 ? -a : a;}
template <class T> inline T max1(T a, T b, T c = -1234567, T d = -1234567) {
	T ans =  a > b ? a : b;
	if(c != -1234567) ans = max1(ans, c);
	if(d != -1234567) ans = max1(ans, d);
	return ans;
}
template <class T> inline T min1(T a, T b, T c = -1234567, T d = -1234567) {
	T ans = a < b ? a : b;
	if(c != -1234567) ans = min(ans, c);
	if(d != -1234567) ans = min(ans, d);
	return ans;
}
template <class T> inline T gcd1(T a, T b) {
	if(a < b) swap(a, b);
	if(a % b == 0) return b;
	return gcd1(b, a % b);
}
template <class T> inline T lb(T num) {return num & (-num); }
inline int jud(double a, double b){
	if(abs(a) < eps && abs(b) < eps) return 0;
	else if(abs1(a - b) / abs1(a) < eps) return 0;
	if(a < b) return -1;
	return 1;
}
template <typename t>
inline int jud(t a, t b){
	if(a < b) return -1;
	if(a == b) return 0;
	return 1;
}
template <typename it, typename t1>
inline int find(t1 val, it a, int na, bool f_small = 1, bool f_lb = 1){
	int be = 0, en = na - 1;
	if(*a <= *(a + na - 1)){
		if(f_lb == 0) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != 1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != -1) en = mid;
			else be = mid + 1;
		}
		if(f_small && jud(*(a + be), val) == 1) be--;
		if(!f_small && jud(*(a + be), val) == -1) be++;
	} else {
		if(f_lb) while(be < en){
			int mid = (be + en + 1) / 2;
			if(jud(*(a + mid), val) != -1) be = mid;
			else en = mid - 1;
		}else while(be < en){
			int mid = (be + en) / 2;
			if(jud(*(a + mid), val) != 1) en = mid;
			else be = mid + 1;
		}
		if(!f_small && jud(*(a + be), val) == -1) be--;
		if(f_small && jud(*(a + be), val) == 1) be++;
	}
	return be;
}
inline int bitnum(ull nValue){
    nValue = ((0xaaaaaaaaaaaaaaaaull & nValue)>>1) + (0x5555555555555555ull & nValue);
    nValue = ((0xccccccccccccccccull & nValue)>>2) + (0x3333333333333333ull & nValue);
    nValue = ((0xf0f0f0f0f0f0f0f0ull & nValue)>>4) + (0x0f0f0f0f0f0f0f0full & nValue);
    nValue = ((0xff00ff00ff00ff00ull & nValue)>>8) + (0x00ff00ff00ff00ffull & nValue);
    nValue = ((0xffff0000ffff0000ull & nValue)>>16) + (0x0000ffff0000ffffull & nValue);
    nValue = ((0xffffffff00000000ull & nValue)>>32) + (0x00000000ffffffffull & nValue);
	return nValue;
}
long long pow(long long n, long long m, long long mod = 0){
	long long ans = 1;
	long long k = n;
	while(m){
		if(m & 1) {
			ans *= k;
			if(mod) ans %= mod;
		}
		k *= k;
		if(mod) k %= mod;
		m >>= 1;
	}
	return ans;
}

//.........................mi.......feng.......xian.......wai.......jin.......zhi.......challenge...............................................

const int maxn = 250;
const ll mod = 1000000007;
int n, col;
ll have[maxn];
int dp[5][maxn * 12][maxn * 4];
ll c[3000][3000];
ll stat1[5][maxn * 4][maxn * 4];
int radd[5][3][maxn * 4][maxn * 4];

int main(){
//	time_t be = clock();
	ios_base::sync_with_stdio(0);
	for(int i = 0; i < 2500; i++) {
		c[i][0] = 1;
		for(int j = 1; j <= i; j++) {
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
			if(c[i][j] > mod) c[i][j] -= mod;
		}
	}

//	freopen("input.txt", "r", stdin);
	scanf("%d%d", &n, &col);
	have[0] = 1;
	for(int i = 1; i <= n; i++) have[i] = have[i - 1] + 3;

/*	cnt1[0][0] = 1;
	cnt1[1][0] = 1; cnt1[1][1] = 3; cnt1[1][2] = 1;
	for(int i = 2; i <= 4 * n; i++) {
		cnt1[i][0] = 1;
		for(int j = 1; j <= col; j++) {
			cnt1[i][j] += cnt1[i - 1][j];
			cnt1[i][j] += cnt1[i - 1][j - 1] * 3 % mod;
			if(j >= 2) cnt1[i][j] += cnt1[i - 1][j - 2];
			cnt1[i][j] %= mod;
		}
	} */

	// most tough part
	for(int i = 0; i < 5; i++) {
		ll all = col - i;
		if(all < 0) break;
		for(int t = 0; t <= n * 12; t++) dp[i][t][0] = c[t][all];
		for(int j = 1; j <= n * 4; j++) for(int t = 0; t <= n * 12 - j * 2; t++) {
			ll ans1 = (ll)dp[i][t + 2][j - 1] + dp[i][t + 1][j - 1] - dp[i][t][j - 1];
			if(ans1 < 0) ans1 += mod;
			while(ans1 > mod) ans1 -= mod;
			dp[i][t][j] = ans1;
		}
	}

	for(int i = -1; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++){
		int cnt = n * 4; int add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 + j11 + k11;
		pii be = mpr(cnt, n * 4 - (max(i11, j11) + max(k11, j11)) - i11 - k11);
		stat1[add][be.first][be.second]++;
		add++;
		stat1[add][be.first][be.second]++;
		radd[add][0][be.first][be.second]++;
		radd[add][0][be.first - min(i11, k11)][be.second]--;
		radd[add][1][be.first - min(i11, k11)][be.second]++;
		radd[add][1][be.first - max(i11, k11)][be.second - abs(i11 - k11)]--;
		radd[add][2][be.first - max(i11, k11)][be.second - abs(i11 - k11)]++;
		radd[add][2][be.first - n][be.second - abs(i11 - k11) - 2 * (n - max(i11, k11))]--;
	}
	for(int i = 0; i <= 4; i++) for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) {
		for(int t = 0; t < 3; t++) {
			radd[i][t][j][k] += radd[i][t][j + 1][k + t], stat1[i][j][k] += radd[i][t][j + 1][k + t];
			if(radd[i][t][j][k] > mod) radd[i][t][j][k] -= mod;
			if(stat1[i][j][k] > mod) stat1[i][j][k] -= mod;
		}
	}
	for(int i = 0; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++) {
		int cnt = n * 4; ll add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 * 2 + j11 + k11;
		stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] += 4;
		if(stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] > mod)
			stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] -= mod;
	}
	if(col >= 2) for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) {
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] += 2;
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] %= mod;
	}
	ll ans = 0;

	for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) for(int t = 0; t < 5; t++) if(stat1[t][k][j] && t <= col){
		ans += dp[t][k * 3 - j * 2][j] * stat1[t][k][j] % mod;
		if(ans > mod) ans -= mod;
/*		for(int i = max(0, col - t - j * 2); i <= col - t; i++){
			if(i > k * 3) break;
			ans += c[k * 3 - j * 2][i] * cnt1[j][col - i - t] % mod * stat1[t][k][j] % mod;
			if(ans > mod) ans -= mod;
		}*/
	}
/*	for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) for(int t = 0; t < 5; t++) if(stat1[t][k][j] && t <= col){
		for(int i = max(0, col - t - j * 2); i <= col - t; i++){
			if(i > k * 3) break;
			dp[t + i][j] += c[k * 3 - j * 2][i] * stat1[t][k][j] % mod;
			if(dp[t + i][j] > mod) dp[t + i][j] -= mod;
//			ans += c[k * 3 - j * 2][i] * cnt1[j][col - i - t] % mod * stat1[t][k][j] % mod;
//			if(ans > mod) ans -= mod;
		}
	} */

/*	for(int i = 1; i <= col; i++) {
		int now = i & 1, last = 1 - now;
		for(int j = 0; j < n * 4; j++) for(int t = 0; t < n * 4; t++) {
			if(j == 0) dp[now][j][t] = cnt1[t][i];
			else dp[now][j][t] = dp[now][j - 1][t] + dp[last][j - 1][t];
			if(dp[now][j][t] > mod) dp[now][j][t] -= mod;
			if(i >= col - 4 && stat1[col - i][j][t]) {
				ans += dp[now][j][t] * stat1[col - i][j][t] % mod;
				if(ans > mod) ans -= mod;
			}
		}
	}*/
	for(ll i = 1; i <= col; i++) ans = ans * i % mod;
	cout << ans << endl;
/*	time_t en = clock();
	cout << double ((en - be)) /  CLOCKS_PER_SEC << endl; */

	return 0;
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int C[205][205],n,m;
LL f[205][205][5];
LL dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	LL &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+dfs(x-1,y-i,z)*C[3*z-2*j][i-j]*C[z-(z!=4)][j])%pri;
	if(z==1)
		return ret=ret+(y==1);
	if(z==2)
		return ret=(ret+dfs(x,y-1,1)*2-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=ret+dfs(x,y-1,2)*2;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1))%pri;
		ret=ret-dfs(x,y-2,1)*3+pri*3+(y==3);
		ret=(ret+dfs(x,y-1,1)*2+pri-(y==2)*2)%pri;
	}
	if(z==4)
	{
		ret=ret+dfs(x,y-1,3)*4-dfs(x,y-2,2)*4;
		for(int i=0;i<y-1;i++)
			ret=ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri+pri;
		ret=ret+dfs(x,y-3,1)*4-(y==4)+pri+(y==3)*4;
		ret=(ret+dfs(x,y-1,2)*4-dfs(x,y-2,1)*8-(y==2)*2+pri*8)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=(LL)q*i%pri;
	printf("%d\n",q);
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <queue>
#include <map>
#include <sstream>
#include <stack>
#include <cassert>
#include <ctime>
#include <cmath>
#include <typeinfo>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

#define pb push_back
#define sz(x) ((x).size())
#define mp make_pair
#define x first
#define y second

const int N = 210;
const int M = 300005;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll oo = 0x3f3f3f3f3f3f3f3fll;
const double eps = 1e-6;

int n, k;

ll C[N][N], dp[N][N][5][3];

int getNum(int cur){
    if(cur == 4) return 2;
    return 4 - cur;
}

int getCon(int cur){
    if(cur == 0) return 4;
    if(cur == 1) return 2;
    if(cur == 2) return 1;
    return 0;
}

ll dfs(int n, int k, int cur, int type){
    if(k == 0) return 1;
    ll & ret = dp[n][k][cur][type];
    if(ret + 1) return ret;
    ret = 0;
    if(type == 0){
        int num = getNum(cur);
        for(int i = 0; i <= k && i <= num; i++){
            (ret += dfs(n - 1, k - i, cur, 2) * C[num][i]) %= mod;
        }
    }
    if(type == 1){
        if(n == 0)
            return ret = 0;
        int num = getNum(cur) * 2;
        int con = getCon(cur);
        for(int i = 0; i <= con && i <= k; i++)
            for(int j = 0; j <= num - i * 2 && j + i <= k; j++){
                (ret += dfs(n, k - i - j, cur, 0) * C[con][i] * C[num - i * 2][j]) %= mod;
            }
    }
    if(type == 2){
        (ret += dfs(n, k, cur, 1)) %= mod;
        if(cur == 0){
            if(k >= 1){
                (ret += dfs(n, k - 1, 1, 1) * 4) %= mod;
                (ret += dfs(n, k - 1, 2, 1) * 4) %= mod;
            }
            if(k >= 2){
                (ret += dfs(n, k - 2, 2, 1) * 4) %= mod;
                (ret += dfs(n, k - 2, 3, 1) * 8) %= mod;
                (ret += dfs(n, k - 2, 4, 1) * 2) %= mod;
                if(k == 2)
                    ret += 2, ret %= mod;
            }
            if(k >= 3){
                (ret += dfs(n, k - 3, 3, 1) * 4) %= mod;
                if(k == 3)
                    ret += 4, ret %= mod;
            }
            if(k == 4)
                ret++, ret %= mod;
        }
        if(cur == 1){
            if(k >= 1){
                (ret += dfs(n, k - 1, 2, 1) * 2) %= mod;
                (ret += dfs(n, k - 1, 3, 1) * 2) %= mod;
                (ret += dfs(n, k - 1, 4, 1) * 1) %= mod;
            }
            if(k >= 2){
                if(k == 2)
                    ret += 2, ret %= mod;
                (ret += dfs(n, k - 2, 3, 1) * 3) %= mod;
            }
            if(k == 3)
                ret++, ret %= mod;
        }
        if(cur == 2){
            if(k >= 1){
                (ret += dfs(n, k - 1, 3, 1) * 2) %= mod;
                if(k == 1)
                    ret++, ret %= mod;
            }
            if(k == 2)
                ret++, ret %= mod;
        }
        if(cur == 3){
            if(k == 1)
                ret++, ret %= mod;
        }
        if(cur == 4){
            if(k >= 1){
                (ret += (dfs(n, k - 1, 3, 1) * 2)) %= mod;
            }
            if(k >= 2){
                if(k == 2)
                    ret++, ret %= mod;
            }
        }
    }
    return ret;
}

int main(){
    for(int i = 0; i < N; i++){
        C[i][0] = C[i][i] = 1;
        for(int j = 1; j < i; j++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
    }
    memset(dp, -1, sizeof(dp));
    scanf("%d%d", &n, &k);
    ll ret = 1;
    for(int i = 1; i <= k; i++)
        (ret *= i) %= mod;
    ret = ret * dfs(n, k, 0, 2) % mod;
    cout << ret << endl;
    return 0;
}

#include <iostream>
#include <fstream>
#include <cstdio>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <numeric>
#include <utility>
#include <functional>
#include <limits>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef pair<int,int> pii;
typedef vector<vector<int> > graph;

const double pi = acos(-1.0);

#define oned(a, x1, x2) { cout << #a << ":"; for(int _i = (x1); _i < (x2); _i++){ cout << " " << a[_i]; } cout << endl; }
#define twod(a, x1, x2, y1, y2) { cout << #a << ":" << endl; for(int _i = (x1); _i < (x2); _i++){ for(int _j = (y1); _j < (y2); _j++){ cout << (_j > y1 ? " " : "") << a[_i][_j]; } cout << endl; } }

#define mp make_pair
#define pb push_back
#define fst first
#define snd second

#define MAXN 205
#define MAXK 2500
#define MAXP 15

int n, k;
ll dp[5][MAXN][MAXK], F[MAXN], C[MAXP][MAXP], mod = 1000000007;

inline void Add(ll &a, ll v) {
    a = (a+v) % mod;
}

int main() {
    F[0] = 1;
    for(ll i = 1; i < MAXN; i++) {
        F[i] = (F[i-1]*i) % mod;
    }

    C[0][0] = 1;
    for(int i = 1; i < MAXP; i++) {
        for(int j = 0; j <= i; j++) {
            C[i][j] = (C[i-1][j] + (j?C[i-1][j-1]:0))%mod;
        }
    }

    dp[0][0][0] = 1;
    dp[0][0][1] = 1;

    dp[1][0][0] = 1;
    dp[1][0][1] = 2;
    dp[1][0][2] = 1;

    dp[2][0][0] = 1;
    dp[2][0][1] = 3;
    dp[2][0][2] = 1;

    dp[3][0][0] = 1;
    dp[3][0][1] = 5;
    dp[3][0][2] = 5;
    dp[3][0][3] = 1;

    dp[4][0][0] = 1;
    dp[4][0][1] = 8;
    dp[4][0][2] = 16;
    dp[4][0][3] = 8;
    dp[4][0][4] = 1;

    for(int i = 1; i < MAXN; i++) {
        for(int j = 0; j <= 12*i+4; j++) {
            // Case 0
            if(j==1) {
                Add(dp[0][i][j], 1);
            }
            for(int s = 0; s <= min(3,j); s++) {
                Add(dp[0][i][j], C[3][s]*dp[0][i-1][j-s]);
            }

            // Case 1
            if(j==2) {
                Add(dp[1][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[1][i][j], ((2*C[3][s])%mod)*dp[0][i-1][j-1-s]);
                }
            }
            for(int s = 0; s <= min(6,j); s++) {
                Add(dp[1][i][j], C[6][s]*dp[1][i-1][j-s]);
            }

            // Case 2
            if(j==1) {
                Add(dp[2][i][j], 1);
            }
            if(j==2) {
                Add(dp[2][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[2][i][j], ((2*C[3][s])%mod)*dp[0][i-1][j-1-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j>=l) {
                    for(int s = 0; s <= min(6-2*l,j-l); s++) {
                        Add(dp[2][i][j], C[6-2*l][s]*dp[2][i-1][j-l-s]);
                    }
                }
            }

            // Case 3
            if(j==2) {
                Add(dp[3][i][j], 2);
            }
            if(j==3) {
                Add(dp[3][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[3][i][j], ((2*C[3][s])%mod)*dp[0][i-1][j-1-s]);
                }
            }
            if(j>=2) {
                for(int s = 0; s <= min(3,j-2); s++) {
                    Add(dp[3][i][j], ((3*C[3][s])%mod)*dp[0][i-1][j-2-s]);
                }
            }
            if(j>=1) {
                for(int s = 0; s <= min(6,j-1); s++) {
                    Add(dp[3][i][j], C[6][s]*dp[1][i-1][j-1-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= 1+l) {
                    for(int s = 0; s <= min(6-2*l,j-1-l); s++) {
                        Add(dp[3][i][j], ((2*C[6-2*l][s])%mod)*dp[2][i-1][j-1-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 2; l++) {
                if(j >= l) {
                    for(int s = 0; s <= min(9-2*l,j-l); s++) {
                        Add(dp[3][i][j], ((C[2][l]*C[9-2*l][s])%mod)*dp[3][i-1][j-l-s]);
                    }
                }
            }

            // Case 4
            if(j==2) {
                Add(dp[4][i][j], 2);
            }
            if(j==3) {
                Add(dp[4][i][j], 4);
            }
            if(j==4) {
                Add(dp[4][i][j], 1);
            }
            if(j>=2) {
                for(int s = 0; s <= min(3,j-2); s++) {
                    Add(dp[4][i][j], ((8*C[3][s])%mod)*dp[0][i-1][j-2-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= l+1) {
                    for(int s = 0; s <= min(6-2*l,j-1-l); s++) {
                        Add(dp[4][i][j], ((4*C[6-2*l][s])%mod)*dp[2][i-1][j-1-l-s]);
                    }
                }
            }
            if(j>=3) {
                for(int s = 0; s <= min(3,j-3); s++) {
                    Add(dp[4][i][j], ((4*C[3][s])%mod)*dp[0][i-1][j-3-s]);
                }
            }
            if(j>=2) {
                for(int s = 0; s <= min(6,j-2); s++) {
                    Add(dp[4][i][j], ((2*C[6][s])%mod)*dp[1][i-1][j-2-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= l+2) {
                    for(int s = 0; s <= min(6-2*l,j-2-l); s++) {
                        Add(dp[4][i][j], ((4*C[6-2*l][s])%mod)*dp[2][i-1][j-2-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 2; l++) {
                if(j >= l+1) {
                    for(int s = 0; s <= min(9-2*l,j-1-l); s++) {
                        Add(dp[4][i][j], ((C[2][l]*4*C[9-2*l][s])%mod)*dp[3][i-1][j-1-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 4; l++) {
                if(j >= l) {
                    for(int s = 0; s <= min(12-2*l,j-l); s++) {
                        Add(dp[4][i][j], ((C[4][l]*C[12-2*l][s])%mod)*dp[4][i-1][j-l-s]);
                    }
                }
            }
        }
    }

//  freopen("input.in", "r", stdin);
    while(cin >> n >> k) {
        cout << (dp[4][n][k] * F[k]) % mod << endl;
    }
}

/*
 * Author:  Eyelids
 * Created Time:  2013/8/19 0:21:24
 * File Name: 336E.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
#include<memory.h>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
#define mod 1000000007
int n, m;
int f[210][210][10][10], a[10], b[10];
int c[210][210];
inline void Add(int &a1, int b1) {
        a1 += b1;
        if (a1 >= mod) a1 -= mod;
}
inline int Mul(int a, int b) {
        lint ret = a;
        ret *= b;
        return (ret % mod);
}

int Calc(int n, int m, int cur, int type) {
        int ret = f[n][m][cur][type];
        if (ret != -1) return ret;

        ret = 0;
        if (type == 0) {
            int bits = a[cur];
            for (int i = 0; (i <= m) && (i <= bits); i ++)
                Add(ret, Mul(Calc(n - 1, m - i, cur, 2), c[bits][i]));
        }

        if (type == 1) {
            if (n == 0)
                return (m == 0) ? 1 : 0;
            int bits = a[cur] << 1, cons = b[cur];
            for (int i = 0; (i <= cons) && (i <= m); i ++)
                for (int j = 0; (j <= bits - 2 * i) && (j + i <= m); j ++)
                    Add(ret, Mul(Calc(n, m - i - j, cur, 0), Mul(c[cons][i], c[bits - 2 * i][j])));
        }

        if (type == 2) {
            Add(ret, Calc(n, m, cur, 1));
            if (cur == 0) {
                if (m >= 1) {
                    Add(ret, Mul(Calc(n, m - 1, 1, 1), 4));
                    Add(ret, Mul(Calc(n, m - 1, 2, 1), 4));
                }
                if (m >= 2) {
                    Add(ret, Mul(Calc(n, m - 2, 4, 1), 2));
                    Add(ret, Mul(Calc(n, m - 2, 2, 1), 4));
                    Add(ret, Mul(Calc(n, m - 2, 3, 1), 8));
                    if (m == 2) Add(ret, 2);
                }
                if (m >= 3) {
                    Add(ret, Mul(Calc(n, m - 3, 3, 1), 4));
                    if (m == 3) Add(ret, 4);
                }
                if (m == 4) Add(ret, 1);
            }
            if (cur == 1) {
                if (m >= 1) {
                    Add(ret, Calc(n, m - 1, 4, 1));
                    Add(ret, Mul(Calc(n, m - 1, 2, 1), 2));
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                }
                if (m >= 2) {
                    Add(ret, Mul(Calc(n, m - 2, 3, 1), 3));
                    if (m == 2) Add(ret, 2);
                }
                if (m == 3)
                    Add(ret, 1);
            }
            if (cur == 2) {
                if (m >= 1) {
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                    if (m == 1) Add(ret, 1);
                }
                if (m == 2)
                    Add(ret, 1);
            }
            if (cur == 3 && m == 1) Add(ret, 1);
            if (cur == 4) {
                if (m >= 1)
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                if (m == 2)
                    Add(ret, 1);
            }
        }

        f[n][m][cur][type] = ret;
        //cout <<n<<" "<<m<<" "<<cur<<" "<<type<<" "<<f[n][m][cur][type]<<endl;
        return ret;
}

int main(){
        scanf("%d%d", &n, &m);

        a[0] = 4, a[1] = 3, a[2] = 2, a[3] = 1, a[4] = 2;
        b[0] = 4, b[1] = 2, b[2] = 1, b[3] = 0, b[4] = 0;
        for (int i = 0; i <= 200; i ++) {
            c[i][0] = 1;
            for (int j = 1; j <= i; j ++)
                Add(c[i][j], c[i - 1][j]), Add(c[i][j], c[i - 1][j - 1]);
        }

        lint fact = 1;
        for (int i = 1; i <= m; i ++) fact = Mul(fact, i);

        memset(f, -1, sizeof(f));
        printf("%d\n", Mul(fact, Calc(n, m, 0, 2)));

        return 0;
}

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define ll long long
using namespace std;
const ll mod=(ll)(1e9+7);
ll f[210];
ll dp[210][210][5];
ll c[210][210];
int n,m;
ll dfs(int x,int y,int z){
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	ll &ret=dp[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;++i)
		for(int j=0;j<=z-(z!=4)&&j<=i;++j)
			ret=(ret+dfs(x-1,y-i,z)*c[3*z-2*j][i-j]*c[z-(z!=4)][j])%mod;
	if(z==1)return ret=ret+(y==1);
	if(z==2)return ret=(ret+dfs(x,y-1,1)*2-(y==2)+(y==1))%mod;
	if(z==3){
		ret=ret+dfs(x,y-1,2)*2;
		for(int i=0;i<y;++i)
			ret=(ret+dfs(x,i,1)*dfs(x,y-i-1,1))%mod;
		ret=ret-dfs(x,y-2,1)*3+mod*3+(y==3);
		ret=(ret+dfs(x,y-1,1)*2+mod-(y==2)*2)%mod;
	}
	if(z==4){
		ret=ret+dfs(x,y-1,3)*4-dfs(x,y-2,2)*4;
		for(int i=0;i<y-1;++i)
			ret=ret-dfs(x,i,1)*dfs(x,y-i-2,1)*2%mod+mod;
		ret=ret+dfs(x,y-3,1)*4-(y==4)+mod+(y==3)*4;
		ret=(ret+dfs(x,y-1,2)*4-dfs(x,y-2,1)*8-(y==2)*2+mod*8)%mod;
	}
	return ret;
}
int main(){
	for(int i=0;i<=15;++i){
		c[i][0]=1;
		for(int j=1;j<=i;++j)
			c[i][j]=c[i-1][j]+c[i-1][j-1];
	}
	f[0]=1;
	for(int i=1;i<=200;++i)
		f[i]=f[i-1]*i%mod;
	scanf("%d%d",&n,&m);
	printf("%d",dfs(n+1,m,4)*f[m]%mod);
	return 0;
}

#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <vector>
#include <string>
#include <set>
#include <map>
#include <cassert>
#include <ctime>

using namespace std;

#ifdef WIN32
    #define LLD "%I64d"
#else
    #define LLD "%lld"
#endif

typedef pair<int, int> pii;
typedef long long ll;
typedef vector<int> vi;
typedef vector<vi> vvi;
typedef vector<bool> vb;
typedef vector<vb> vvb;
typedef vector<ll> vll;
typedef vector<vll> vvll;

ll rdtsc() {
    ll tmp;
    asm("rdtsc" : "=A"(tmp));
    return tmp;
}

#define TASKNAME "text"
#define pb push_back
#define mp make_pair
#define EPS (1e-9)
#define INF ((int)1e9)
#define sqr(x) ((x) * (x))
#define eprintf(...) fprintf(stderr, __VA_ARGS__)
#define sz(x) ((int)(x).size())

const int MOD = (int)1e9 + 7;

inline void add(int &x, int y) {
	if ((x += y) >= MOD)
		x -= MOD;
}

inline int mult(int x, int y) {
	return (long long)x * y % MOD;
}

const int maxn = 201;
int d[maxn][maxn][1 << 4];

const int maxCntIds = (int)1e5;
int cntIds;
int prec[maxCntIds][3];

void printMask(int mask) {
	for (int i = 0; i < 12; i++)
		eprintf("%d%c", ((mask >> i) & 1), " \n"[i == 11]);
}

void gen(int iter, int mask, int left, int putk) {
	if (iter == 12 + 4 + 4 + 4) {
		assert(cntIds < maxCntIds);
		prec[cntIds][0] = mask, prec[cntIds][1] = left, prec[cntIds][2] = putk;
		cntIds++;
		return;
	}
	gen(iter + 1, mask, left, putk);
	if (iter < 12)
		gen(iter + 1, mask ^ (1 << iter), left, putk + 1);
	else {
		if (iter - 12 < 4) {
			int addMask = (7 << (3 * (iter - 12))) ^ (7 << (3 * ((iter - 12 + 1) & 3)));
			if (!(addMask & mask))
				gen(iter + 1, mask ^ addMask, left ^ (1 << (iter - 12)) ^ (1 << ((iter - 12 + 1) & 3)), putk + 1);
		} else {
			if (iter - 16 < 4) {
				int addMask = (7 << (3 * (iter - 16)));
				if (!(addMask & mask))
					gen(iter + 1, mask ^ addMask, left ^ (1 << (iter - 16)), putk + 1);
			} else {
				int addMask = (1 << (3 * (iter - 20))) ^ (1 << ((3 * (iter - 20) + 11) % 12));
				if (!(addMask & mask))
					gen(iter + 1, mask ^ addMask, left, putk + 1);
			}
		}
	}
}

void countPrec() {
	cntIds = 0;
	gen(0, 0, 0, 0);
	eprintf("cntIds = %d\n", cntIds);
}

const int cnt0 = 8;
const int mask0[cnt0] = {1, 2, 4, 8, 3, 6, 12, 9};

int gen0(int iter, int taken, int left) {
	if (left > cnt0 - iter)
		return 0;
	if (iter == cnt0)
		return 1;
	int ans = gen0(iter + 1, taken, left);
	if (left && !(taken & mask0[iter]))
		add(ans, gen0(iter + 1, taken | mask0[iter], left - 1));
	return ans;
}

int better[16] = {0, 1, 1, 3, 1, 5, 3, 7, 1, 3, 5, 7, 3, 7, 7, 15};

void countD(int n0, int k0) {
	countPrec();

	for (int k = 0; k <= k0; k++)
		for (int taken = 0; taken < (1 << 4); taken++) {
			d[0][k][taken] = gen0(0, taken, k);
			if (better[taken] < taken) {
				assert(d[0][k][taken] == d[0][k][better[taken]]);
				continue;
			}
		}

	vector<vector<pair<pii, int> > > pairs(1 << 4);
	for (int taken = 0; taken < (1 << 4); taken++) {
		int maskFail = 0;
		for (int i = 0; i < 4; i++) {
			if (!((taken >> i) & 1))
				continue;
			maskFail ^= (7 << (3 * i));
		}

		for (int i = 0; i < cntIds; i++) {
			if (!(maskFail & prec[i][0]))
				pairs[taken].pb(mp(mp(prec[i][1], prec[i][2]), 1));
		}

		sort(pairs[taken].begin(), pairs[taken].end());

		int newlen = 0;
		for (int i = 0; i < sz(pairs[taken]);) {
			int i0 = i;
			while (i < sz(pairs[taken]) && pairs[taken][i].first == pairs[taken][i0].first)
				i++;
			pairs[taken][newlen++] = mp(pairs[taken][i0].first, i - i0);
		}

		//eprintf("%d %d\n", sz(pairs[taken]), newlen);
		pairs[taken].resize(newlen);
	}

	for (int n = 1; n <= n0; n++) {
		for (int k = 0; k <= k0; k++) {
			for (int taken = 0; taken < (1 << 4); taken++) {
				int &cur = d[n][k][taken];
				cur = 0;
				if (!k) {
					cur = 1;
					continue;
				}
				if (better[taken] < taken) {
					cur = d[n][k][better[taken]];
					continue;
				}
				int maskFail = 0;
				for (int i = 0; i < 4; i++) {
					if (!((taken >> i) & 1))
						continue;
					maskFail ^= (7 << (3 * i));
				}

				for (int id = 0; id < sz(pairs[taken]); id++) {
					int left = pairs[taken][id].first.first, putk = pairs[taken][id].first.second, cnt = pairs[taken][id].second;
					if (putk > k)
						continue;
					left |= taken;
					cur = (cur + (ll)cnt * d[n - 1][k - putk][left]) % MOD;
				}
			}
		}
	}
}

bool solve() {
	int n, k;
	if (scanf("%d%d", &n, &k) < 1)
		return 0;

	countD(n, k);
	int res = d[n][k][0];
	for (int i = 1; i <= k; i++)
		res = mult(res, i);
	printf("%d\n", res);
	return 1;
}

int main() {
	srand(rdtsc());
#ifdef DEBUG
	freopen(TASKNAME".in", "r", stdin);
	freopen(TASKNAME".out", "w", stdout);
#endif

	while (1) {
		if (!solve())
			break;
		#ifdef DEBUG
			eprintf("%.18lf\n", (double)clock() / CLOCKS_PER_SEC);
		#endif
	}
	return 0;
}

#include <cstdio>
#include <algorithm>
using namespace std;

typedef long long ll;

const int mod = 1000000007;

const int Maxn = 205;
const int Maxp = 5;
const int lft[Maxp] = {4, 3, 2, 1, 2};
const int inter[Maxp] = {4, 2, 1, 0, 0};
const int Maxm = 2 * Maxp;

int C[Maxm][Maxm];
int dp[Maxn][Maxn][Maxp][3];
int n, k;
int res;

int Get(int v, int k, int tk, int opt)
{
	if (dp[v][k][tk][opt] == -1) {
		int res = 0;
		if (opt == 0) {
			res = Get(v, k, tk, 1);
			if (tk == 0) {
				if (k >= 1) {
					res = (res + ll(Get(v, k - 1, 1, 1)) * 4ll % ll(mod)) % mod;
					res = (res + ll(Get(v, k - 1, 2, 1)) * 4ll % ll(mod)) % mod;
				}
				if (k >= 2) {
					res = (res + ll(Get(v, k - 2, 2, 1)) * 4ll % ll(mod)) % mod;
					res = (res + ll(Get(v, k - 2, 4, 1)) * 2ll % ll(mod)) % mod;
					res = (res + ll(Get(v, k - 2, 3, 1)) * 8ll % ll(mod)) % mod;
				}
				if (k == 2) res = (res + 2) % mod;
				if (k >= 3) res = (res + ll(Get(v, k - 3, 3, 1)) * 4ll % ll(mod)) % mod;
				if (k == 3) res = (res + 4) % mod;
				if (k == 4) res = (res + 1) % mod;
			} else if (tk == 1) {
				if (k >= 1) {
					res = (res + ll(Get(v, k - 1, 2, 1)) * 2ll % ll(mod)) % mod;
					res = (res + Get(v, k - 1, 4, 1)) % mod;
					res = (res + ll(Get(v, k - 1, 3, 1)) * 2ll % ll(mod)) % mod;
				}
				if (k >= 2) res = (res + ll(Get(v, k - 2, 3, 1)) * 3ll % ll(mod)) % mod;
				if (k == 2) res = (res + 2) % mod;
				if (k == 3) res = (res + 1) % mod;
			} else if (tk == 2) {
				if (k >= 1) res = (res + ll(Get(v, k - 1, 3, 1)) * 2ll % ll(mod)) % mod;
				if (k == 1) res = (res + 1) % mod;
				if (k == 2) res = (res + 1) % mod;
			} else if (tk == 3) {
				if (k == 1) res = (res + 1) % mod;
			} else if (tk == 4) {
				if (k >= 1) res = (res + ll(Get(v, k - 1, 3, 1)) * 2ll % ll(mod)) % mod;
				if (k == 2) res = (res + 1) % mod;
			}
		} else if (opt == 1)
			if (v == 0) res = k == 0;
			else {
				int parts = 2 * lft[tk], in = inter[tk];
				for (int i = 0; i <= in && i <= k; i++)
					for (int j = 0; 2 * i + j <= parts && i + j <= k; j++)
						res = (res + ll(C[in][i]) * ll(C[parts - 2 * i][j]) % ll(mod) * ll(Get(v, k - i - j, tk, 2)) % ll(mod)) % mod;
			}
		else if (opt == 2) {
			int parts = lft[tk];
			for (int i = 0; i <= parts && i <= k; i++)
				res = (res + ll(C[parts][i]) * ll(Get(v - 1, k - i, tk, 0)) % ll(mod)) % mod;
		}
		dp[v][k][tk][opt] = res;
	}
	return dp[v][k][tk][opt];
}

int main()
{
	for (int i = 0; i < Maxm; i++) {
		C[i][0] = C[i][i] = 1;
		for (int j = 1; j < i; j++) C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
	}
	fill((int*)dp, (int*)dp + Maxn * Maxn * Maxp * 3, -1);
	scanf("%d %d", &n, &k);
	res = Get(n, k, 0, 0);
	for (int i = 2; i <= k; i++) res = ll(res) * ll(i) % ll(mod);
	printf("%d\n", res);
	return 0;
}

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define maxn 205
#define mo 1000000007
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

ll c[maxn][maxn],n,k;

ll f[maxn][maxn][5][3];

const int num[5]={4,3,2,1,2};
const int num1[5]={4,2,1,0,0};

ll get(ll n,ll k,ll cur,ll ty){
    if (k==0) return 1;
    ll &ret=f[n][k][cur][ty];
    if (ret!=-1) return ret; else ret=0;
    if (ty==0){
        ll now=num[cur];
        fo(i,0,min(k,now))
            ret=(ret+get(n-1,k-i,cur,2)*c[now][i]) % mo;
    }
    else if (ty==1){
        if (n==0) return 0;
        ll now=num[cur]*2,now1=num1[cur];
        fo(i,0,min(now1,k))
            fo(j,0,k-i){
                if (j>now-i*2) break;
                ret=(ret+get(n,k-i-j,cur,0)*c[now1][i]*c[now-i*2][j]) % mo;
            }
    }
    else {
        ret=(ret+get(n,k,cur,1)) % mo;
        if (cur==0){
            if (k>=1) ret=(ret+get(n,k-1,1,1)*4+get(n,k-1,2,1)*4) % mo;
            if (k>=2) ret=(ret+get(n,k-2,2,1)*4+get(n,k-2,3,1)*8+get(n,k-2,4,1)*2) % mo;
            if (k>=3) ret=(ret+get(n,k-3,3,1)*4) % mo;
            if (k==2) ret=(ret+2) % mo;
            if (k==3) ret=(ret+4) % mo;
            if (k==4) ret=(ret+1) % mo;
        }
        else if (cur==1){
            if (k>=1) ret=(ret+get(n,k-1,2,1)*2+get(n,k-1,3,1)*2+get(n,k-1,4,1)) % mo;
            if (k>=2) ret=(ret+get(n,k-2,3,1)*3) % mo;
            if (k==2) ret=(ret+2) % mo;
            if (k==3) ret=(ret+1) % mo;
        }
        else if (cur==2){
            if (k>=1) ret=(ret+get(n,k-1,3,1)*2) % mo;
            if (k==1) ret=(ret+1) % mo;
            if (k==2) ret=(ret+1) % mo;
        }
        else if (cur==3){
            if (k==1) ret=(ret+1) % mo;
        }
        else if (cur==4){
            if (k>=1) ret=(ret+get(n,k-1,3,1)*2) % mo;
            if (k==2) ret=(ret+1) % mo;
        }
    }
    return ret;
}

int main(){
    scanf("%I64d%I64d",&n,&k);
    fo(i,0,200) {
        c[i][0]=1;
        c[i][i]=1;
        fo(j,1,i-1)
            c[i][j]=(c[i-1][j-1]+c[i-1][j]) % mo;
    }
    mem(f,255);
    ll ans=get(n,k,0,2);
    fo(i,1,k) ans=ans*i % mo;
    printf("%I64d",ans);
    return 0;
}

#include <cstdio>
using namespace std;

typedef long long ll;
const int mod = 1000000007;
inline int times(int a, int b) {return int(ll(a) * ll(b) % ll(mod));}
inline void add(int &a, int b) {a += b; a %= mod;}

int rot(int bit)
{
	int ff = bit / 16 * 4;
	int bb = bit % 16 * 2;
	int nff = ((ff | (ff >> 8)) ^ ((ff >> 8) << 8));
	int nbb = ((bb | (bb >> 4)) ^ ((bb >> 4) << 4));
	return ((nff << 4) | nbb);
}

const int itri[5] = {0x31, 0xf3, 0x10, 0x20, 0x60};
const int stri[8] = {1, 2, 4, 8, 3, 6, 9, 12};
const int dsz = 256;
int tri[20], block[16];
int comb[1 << 20], cnt[1 << 20], csz;
int n, k;
int dp[2 * dsz][16][dsz];

int main()
{
	for(int i = 0; i < 5; i++)
	{
		tri[4 * i] = itri[i];
		for(int j = 1; j < 4; j++)
			tri[4 * i + j] = rot(tri[4 * i + j - 1]);
	}
	for(int i = 0; i < 16; i++)
	{
		block[i] = 0;
		for(int j = 0; j < 4; j++)
			if(i & (1 << j))
				block[i] |= tri[j];
	}
	csz = 0;
	for(int bit = 0; bit < (1 << 20); bit++)
	{
		int ccomb = 0, ccnt = 0;
		bool ok = true;
		for(int i = 0; ok && i < 20; i++)
			if(bit & (1 << i))
			{
				if(ccomb & tri[i])
					ok = false;
				else
				{
					ccomb |= tri[i];
					ccnt++;
				}
			}
		if(ok)
		{
			comb[csz] = ccomb;
			cnt[csz] = ccnt;
			csz++;
		}
	}

	scanf("%d %d", &n, &k);
	for(int l = 0; l <= 2 * n; l++)
		for(int dir = 0; dir < 16; dir++)
			for(int cnt = 0; cnt <= k; cnt++)
				dp[l][dir][cnt] = 0;
	dp[0][0][0] = 1;

	for(int l = 0; l < 2 * n; l++)
		for(int dir = 0; dir < 16; dir++)
			for(int cc = 0; cc <= k; cc++)
			{
				if(l % 2 == 0)
				{
					for(int i = 0; i < csz; i++)
						if((block[dir] & comb[i]) == 0)
						{
							int ndir = (dir | (comb[i] % 16));
							int ncc = cc + cnt[i];
							if(ncc <= k)
								add(dp[l + 1][ndir][ncc], dp[l][dir][cc]);
						}
				}
				else
				{
					add(dp[l + 1][dir][cc], dp[l][dir][cc]);
					int mask = 15 - dir;
					int dd = mask;
					while(dd)
					{
						int ncc = cc;
						for(int i = 0; i < 4; i++)
							if(dd & (1 << i))
								ncc++;
						if(ncc <= k)
							add(dp[l + 1][dir][ncc], dp[l][dir][cc]);
						dd = (dd - 1) & mask;
					}
				}
			}

	int ans = 0;
	for(int dir = 0; dir < 16; dir++)
		for(int cc = 0; cc <= k; cc++)
		{
			for(int bit = 0; bit < (1 << 8); bit++)
			{
				int dd = dir, ncc = cc;
				bool ok = true;
				for(int i = 0; ok && i < 8; i++)
					if(bit & (1 << i))
					{
						if(dd & stri[i])
							ok = false;
						else
						{
							dd |= stri[i];
							ncc++;
						}
					}
				if(ok && ncc == k)
					add(ans, dp[2 * n][dir][cc]);
			}
		}

	for(int i = 1; i <= k; i++)
		ans = times(ans, i);
	printf("%d\n", ans);

	return 0;
}

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 205
#define mod 1000000007
#define ask(xx, ii) ((xx>>ii-1)&1)
#define add(xx, ii) (xx|(1<<ii-1))
#define ins(xx, yy) (xx = (xx+yy)%mod)
using namespace std ;
typedef long long LL ;

LL N, K, ans ;
LL d1[MAXN][MAXN][16], d2[MAXN][MAXN][16] ;
LL C[21][21] ;
// 放 a 个 有 b 个
void Work1(LL x) ;
void Work2(LL x) ;

void Work2(LL x)
{
	LL i, j, t, to, tmp ;
	if(x == 0) return ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
		{
			if(!d2[x][i][j]) continue ;
			for(t = 1, tmp = 0; t <= 4; t ++)
				if(!ask(j, t)) tmp ++ ;
			to = min(i, tmp) ;
			for(t = 0; t <= to; t ++)
				ins(d1[x-1][i-t][j], d2[x][i][j]*C[tmp][t]) ;
		}
	Work1(x-1) ;
}

void Dfs(LL x, LL rest, LL state, LL now, LL ad)
{
	LL i, j, to, tmp = 0, tmp2 = 0, all ;
	if(now >= 5)
	{
		for(i = 1; i <= 4; i ++)
		{
			if(!ask(state, i) && !ask(state, i%4+1)) tmp ++ ;
			if(!ask(state, i) && ask(state, i%4+1)) tmp2 ++ ;
			if(ask(state, i) && !ask(state, i%4+1)) tmp2 ++ ;
		}
		if(x == 0)
			ins(d2[x][rest][state], ad) ;
		else
		{
			to = min(tmp*2+tmp2, rest) ;
			for(i = 0; i <= to; i ++)
				for(j = 0; j <= min(tmp, i); j ++)
				{
					if((all = tmp2+(tmp-j)*2) >= i-j)
						ins(d2[x][rest-i][state],
						ad*C[tmp][j]%mod*C[all][i-j]%mod) ;
				}
		}
		return ;
	}
	if(!ask(state, now) && rest) Dfs(x, rest-1, add(state, now), now+1, ad) ;
	if(!ask(state, now) && !ask(state, now%4+1))
		Dfs(x, rest-1, add(add(state, now), now%4+1), now+2, ad) ;
	Dfs(x, rest, state, now+1, ad) ;
}

void Work1(LL x)
{
	LL i, j, t ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
			if(d1[x][i][j])
				Dfs(x, i, j, 1, d1[x][i][j]) ;
	Work2(x) ;
}

int main()
{
	LL i, j ;
	scanf("%I64d %I64d", &N, &K) ;
	d1[N][K][0] = 1 ;
	C[0][0] = 1 ;
	for(i = 1; i <= 20; i ++)
		for(j = 1, C[i][0] = 1; j <= i; j ++)
			C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod ;
	Work1(N) ;
	for(i = 0; i <= 15; i ++)
		ans = (ans+d2[0][0][i])%mod ;
	for(i = 1; i <= K; i ++)
		ans = ans*i%mod ;
	printf("%I64d\n", ans) ;
	//system("pause") ;
	return 0 ;
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int C[205][205],n,m;
LL f[205][205][7];
LL dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	LL &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+dfs(x-1,y-i,z)*C[3*z-2*j][i-j]*C[z-(z!=4)][j])%pri;
	if(z==1)
		return ret=ret+(y==1);
	if(z==2)
		return ret=(ret+dfs(x,y-1,1)*2-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=ret+dfs(x,y-1,2)*2;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1))%pri;
		ret=ret-dfs(x,y-2,1)*3+pri*3+(y==3);
		ret=(ret+dfs(x,y-1,1)*2+pri-(y==2)*2)%pri;
	}
	if(z==4)
	{
		ret=ret+dfs(x,y-1,3)*4-dfs(x,y-2,2)*4;
		for(int i=0;i<y-1;i++)
			ret=ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri+pri;
		ret=ret+dfs(x,y-3,1)*4-(y==4)+pri+(y==3)*4;
		ret=(ret+dfs(x,y-1,2)*4-dfs(x,y-2,1)*8-(y==2)*2+pri*8)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=(LL)q*i%pri;
	printf("%d\n",q);
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int C[205][205],n,m;
LL f[205][205][6];
LL dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	LL &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+dfs(x-1,y-i,z)*C[3*z-2*j][i-j]*C[z-(z!=4)][j])%pri;
	if(z==1)
		return ret=ret+(y==1);
	if(z==2)
		return ret=(ret+dfs(x,y-1,1)*2-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=ret+dfs(x,y-1,2)*2;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1))%pri;
		ret=ret-dfs(x,y-2,1)*3+pri*3+(y==3);
		ret=(ret+dfs(x,y-1,1)*2+pri-(y==2)*2)%pri;
	}
	if(z==4)
	{
		ret=ret+dfs(x,y-1,3)*4-dfs(x,y-2,2)*4;
		for(int i=0;i<y-1;i++)
			ret=ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri+pri;
		ret=ret+dfs(x,y-3,1)*4-(y==4)+pri+(y==3)*4;
		ret=(ret+dfs(x,y-1,2)*4-dfs(x,y-2,1)*8-(y==2)*2+pri*8)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=(LL)q*i%pri;
	printf("%d\n",q);
}

/****************************************\
* Author : ztx
* Title  :
* ALG    :
* CMT    :
* Time   :
\****************************************/

#include <cstdio>
#define Rep(i,l,r) for(i=(l);i<=(r);i++)
#define Rev(i,r,l) for(i=(r);i>=(l);i--)
int CH , NEG ;
template <typename TP>
inline void read(TP& ret) {
    ret = NEG = 0 ; while (CH=getchar() , CH<'!') ;
    if (CH == '-') NEG = true , CH = getchar() ;
    while (ret = ret*10+CH-'0' , CH=getchar() , CH>'!') ;
    if (NEG) ret = -ret ;
}
template <typename TP>
inline void reads(TP& ret) {
	while (ret=getchar() , ret<'!') ;
	while (CH=getchar() , CH>'!') ;
}

#include <cstring>

const int  ansmod  = 1000000007 ;
#define  inc(a,b) {a+=b;if(a>=ansmod)a-=ansmod;}
#define  maxn  210LL//n
#define  maxk  210LL//k
#define  maxs  16LL//��λ01״̬
#define  maxq  5LL//�ĸ�����
#define  maxt  10LL//һ��ת���������8��������

int N , K ;
int g[16][10][16] = {0} ;
int h[5][10][2][2][16] = {0} ;
int f[401][210][16] = {0} ;
int num[16] ;

//���ǰѵ�i�㵽��i+1���Ϊ��������
//���ӵ�i��ת�Ƶ���i+0.5��(���ŵ�ƽ��)�͵�i+0.5�㵽i+1��(ƽ�ŵ�����)
//g[ԭʼ״̬][���Ӽ���������][����Ŀ��״̬]�ķ�����
//h[ǰi������][�����˼���������][��i*2���������Ƿ�ʹ��][��1���������Ƿ�ʹ��][��ʱ��״̬]
//(��i*2��Ҳ����ǰi�������е����һ��������)
//h��������g��
//���g�����������f
//���Ҫ��k�Ľ׳�,��ΪȾɫ���������ͬ,˳��ͬҲ�㲻ͬ

int i , j , k , A , B , use , last , first , now1 , now2 , cnt , can , Time , ans ;
int col[4] = {0} ;

int main() {
//	#define READ
	#ifdef  READ
		freopen("djm.in" ,"r",stdin ) ;
		freopen("djm.out","w",stdout) ;
	#endif
	Rep (A,0,16-1) {
		num[B=A] = 0 ;
		while (B) num[A]+=(B&1) , B>>=1 ;
	}
	Rep (A,0,16-1) {
		memset(h , 0 , sizeof h) ;
		h[1][0][0][0][A]=h[1][1][1][0][A|1]=h[1][2][1][1][A|1]=h[1][1][0][1][A|1]=1;
		if (!(A&1)) h[1][1][1][1][A|1]=1;
		Rep (i,1,3) Rep (use,0,8) Rep (last,0,1) Rep (first,0,1)
			Rep (B,0,16-1) if (h[i][use][last][first][B])
				Rep (now1,0,1) Rep (now2,0,1) {
					if (!now1 && !now2 && !((B>>i)&1))//��ǰ������޲�ʹ����������������ޱ������ǿյ�
						inc(h[i+1][use+1][1][first][B|(1<<i)],h[i][use][last][first][B]);//�Ǿ�����һ����������
					inc(h[i+1][use+now1+now2][now2][first][B|((now1|now2)<<i)],h[i][use][last][first][B]) ;
					if (!last && !now1)
						inc(h[i+1][use+1+now2][now2][first][B|(1<<i)|(1<<(i-1))],h[i][use][last][first][B]);
						//����һ�����޵�������ƴ�ӳ�һ������������
					if (!now1 && !now2 && !((B>>i)&1) && !((B>>(i-1))&1))
						inc(h[i+1][use+1][1][first|(i==1)][B|(1<<i)|(1<<(i-1))],h[i][use][last][first][B]);
						//����������ڵ����޶��ǿյ�,������һ���ܴ�������� = =
				}
		Rep (use,0,8) Rep (B,0,16-1)
			inc(h[4][use+1][1][1][B|9],h[4][use][0][0][B]) ;
		Rep (use,0,8) Rep (B,0,16-1) if (!(B&1)&&!(B&8))
			inc(h[4][use+1][1][1][B|9],h[4][use][0][0][B]) ;
		Rep (use,0,8) Rep (last,0,1) Rep (first,0,1) Rep (B,0,16-1)
			inc(g[A][use][B],h[4][use][last][first][B]) ;
	}
	Rep (A,0,16-1) Rep(B,0,16-1) {
		col[0]=col[1]=col[2]=col[3]=0;
		cnt = 0 ;
		Rep (i , 0 , 4-1)
			col[i] = ((A>>i)&1) , cnt += col[i] ;
		can = true ;
		Rep (i,0,4-1) if ((B>>i)&1) {
			if (col[i] || col[(i+1)%4]) can = false ;
			col[i] = col[(i+1)%4] = true ;
			cnt ++ ;
		}
		if (!can) continue ;
		K = 0 ;
		Rev (i,4-1,0)
			K = (K<<1)|col[i] ;
		f[0][cnt][K] ++ ;
	}
	Rep (i,0,400-1) Rep (j,0,200) Rep (A,0,16-1)
		if (f[i][j][A])
			if (i&1) {
				//������ת�Ƶ�ż��,ͳ�Ƶ���״����������������
				Rep (k,0,8)
					//������������а˸�С������
					//����ת��ʱӦ�ð���������������ƴ���������
						Rep (B,0,16-1)
							inc(f[i+1][j+k][B],(long long)f[i][j][A]*g[A][k][B]%ansmod) ;
			} else {
				//��ż��ת�Ƶ�����,ͳ�Ƶ���״��ƽ����������
				Rep (k,0,16-1)
					//����ֻ���ж��ĸ����Ƿ��������μ���
					inc(f[i+1][j+num[k]][A|k],f[i][j][A]) ;
			}
	//read(Time) ;
	Time = 1 ;
	while (Time --> 0) {
		read(N) , read(K) ;
		int ans = 0 ;
		Rep (A,0,16-1)
			inc(ans,f[2*N][K][A]) ;
		Rep (i,1,K)
			ans = (long long)ans*i%ansmod ;
		printf("%d\n", ans) ;
	}
	#ifdef  READ
		fclose(stdin) ; fclose(stdout) ;
	#else
		getchar() ; getchar() ;
	#endif
	return 0 ;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <utility>

using namespace std;

typedef long long LL;

const int maxn = 205;
const LL mod = 1000000007;

int n, col;
LL have[maxn];
int dp[5][maxn * 12][maxn * 4];
LL c[2510][2510];
LL stat1[5][maxn * 4][maxn * 4];
int radd[5][3][maxn * 4][maxn * 4];

int main()
{
	for(int i = 0; i < 2500; i++) {
		c[i][0] = 1;
		for(int j = 1; j <= i; j++) {
			c[i][j] = c[i - 1][j - 1] + c[i - 1][j];
			if(c[i][j] > mod) c[i][j] -= mod;
		}
	}

	scanf("%d%d", &n, &col);
	have[0] = 1;
	for(int i = 1; i <= n; i++) have[i] = have[i - 1] + 3;

	for(int i = 0; i < 5; i++) {
		LL aLL = col - i;
		if(aLL < 0) break;
		for(int t = 0; t <= n * 12; t++) dp[i][t][0] = c[t][aLL];
		for(int j = 1; j <= n * 4; j++) for(int t = 0; t <= n * 12 - j * 2; t++) {
			LL ans1 = (LL)dp[i][t + 2][j - 1] + dp[i][t + 1][j - 1] - dp[i][t][j - 1];
			if(ans1 < 0) ans1 += mod;
			while(ans1 > mod) ans1 -= mod;
			dp[i][t][j] = ans1;
		}
	}

	for(int i = -1; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++){
		int cnt = n * 4; int add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 + j11 + k11;
		pair <int, int> be = make_pair(cnt, n * 4 - (max(i11, j11) + max(k11, j11)) - i11 - k11);
		stat1[add][be.first][be.second]++;
		add++;
		stat1[add][be.first][be.second]++;
		radd[add][0][be.first][be.second]++;
		radd[add][0][be.first - min(i11, k11)][be.second]--;
		radd[add][1][be.first - min(i11, k11)][be.second]++;
		radd[add][1][be.first - max(i11, k11)][be.second - abs(i11 - k11)]--;
		radd[add][2][be.first - max(i11, k11)][be.second - abs(i11 - k11)]++;
		radd[add][2][be.first - n][be.second - abs(i11 - k11) - 2 * (n - max(i11, k11))]--;
	}
	for(int i = 0; i <= 4; i++) for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) {
		for(int t = 0; t < 3; t++) {
			radd[i][t][j][k] += radd[i][t][j + 1][k + t], stat1[i][j][k] += radd[i][t][j + 1][k + t];
			if(radd[i][t][j][k] > mod) radd[i][t][j][k] -= mod;
			if(stat1[i][j][k] > mod) stat1[i][j][k] -= mod;
		}
	}
	for(int i = 0; i <= n; i++) for(int j = -1; j <= n; j++) for(int k = -1; k <= n; k++) {
		int cnt = n * 4; LL add = 0;
		if(i != -1) add++;
		if(j != -1) add++;
		if(k != -1) add++;
		int i11 = max(0, i), j11 = max(0, j), k11 = max(0, k);
		cnt -= i11 * 2 + j11 + k11;
		stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] += 4;
		if(stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] > mod)
			stat1[add][cnt][4 * n - i11 - max(i11, j11) - max(j11, k11) - max(k11, i11)] -= mod;
	}
	if(col >= 2) for(int i = 0; i <= n; i++) for(int j = 0; j <= n; j++) {
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] += 2;
		stat1[2][n * 4 - i * 2 - j * 2][4 * n - i - j - max(i, j) * 2] %= mod;
	}
	LL ans = 0;

	for(int k = n * 4; k >= 0; k--) for(int j = n * 4; j >= 0; j--) for(int t = 0; t < 5; t++) if(stat1[t][k][j] && t <= col){
		ans += dp[t][k * 3 - j * 2][j] * stat1[t][k][j] % mod;
		if(ans > mod) ans -= mod;
	}

	for(LL i = 1; i <= col; i++) ans = ans * i % mod;
	printf("%I64d\n",ans);

	return 0;
}

#include <cstdlib>
#include <cstdio>
#include <iostream>
#include <cmath>
#include <algorithm>
#include <vector>
#include <set>
#include <map>
#include <cstring>

using namespace std;

typedef long long LL;
typedef unsigned long long ULL;

#define SIZE(x) (int((x).size()))
#define rep(i,l,r) for (int i=(l); i<=(r); i++)
#define repd(i,r,l) for (int i=(r); i>=(l); i--)
#define rept(i,c) for (typeof((c).begin()) i=(c).begin(); i!=(c).end(); i++)

#ifndef ONLINE_JUDGE
#define debug(x) { cerr<<#x<<" = "<<(x)<<endl; }
#else
#define debug(x) {}
#endif

#define MD 1000000007

void su(int &a, int b)
{
	a+=b; if (a>=MD) a-=MD;
}

int bitcount(int x)
{
	int ret=0;
	while (x) x-=x&-x, ret++;
	return ret;
}

int tmask[7]={0,3,6,12,9,15,15};
int tcost[7]={0,1,1,1,1,2,2};
int C[10][10], g[16][13][16], all[16], cs[16][210][3], dp[210][210][16];

void lemon()
{
	int n,m; scanf("%d%d",&n,&m);
	C[0][0]=1;
	rep(i,1,5)
	{
		C[i][0]=C[i][i]=1;
		rep(j,1,i-1) C[i][j]=C[i-1][j-1]+C[i-1][j];
	}
	//dp[h][c][mask]
	//current height h, c triangles, covering section mask
	rep(mask,0,15)
		rep(ti,0,6)
			if ((mask&tmask[ti])==tmask[ti])
				rep(tk,0,15)
					if (((mask^tmask[ti])&tk)==tk)
					{
						int nmask=tmask[ti]|tk, cav=0;
						rep(i,0,3) if ((!(nmask&(1<<i))) && (!(nmask&(1<<((i+1)&3))))) cav|=(1<<i);
						rep(ci,0,15)
						{
							int cover=(ci|((ci&7)<<1)|(ci>>3));
							if ((cav&ci)==ci && (mask&cover)==cover)
							{
								int av[4], tv[4];
								rep(i,0,3) if (nmask&(1<<i)) av[i]=0; else av[i]=3;
								rep(i,0,3) if (ci&(1<<i)) av[i]--, av[(i+1)&3]--;
								rep(t0,0,av[0])
									rep(t1,0,av[1])
										rep(t2,0,av[2])
											rep(t3,0,av[3])
											{
												int cost=tcost[ti]+bitcount(tk)+bitcount(ci)+t0+t1+t2+t3;
												tv[0]=t0; tv[1]=t1; tv[2]=t2; tv[3]=t3;
												int gmask=0; rep(i,0,3) if (tv[i]) gmask|=(1<<i);
												if ((mask&gmask)!=gmask) continue;
												int co=1;
												rep(i,0,3) co=co*C[av[i]][tv[i]];
												rep(mmask,0,15)
													if ((mmask&nmask)==0 && (mmask|nmask|gmask|cover)==mask)
														su(g[mask][cost][mmask],co);
											}
							}
						}
					}

	memset(all,0,sizeof all);
	rep(mask,0,15)
		rep(cost,0,12)
			rep(mmask,0,15)
				if (g[mask][cost][mmask])
				{
					all[mask]++;
					cs[mask][all[mask]][0]=cost;
					cs[mask][all[mask]][1]=mmask;
					cs[mask][all[mask]][2]=g[mask][cost][mmask];
				}

	dp[0][0][0]=1;
	dp[0][1][1]=1; dp[0][1][2]=1; dp[0][1][4]=1; dp[0][1][8]=1;
	dp[0][1][3]=1; dp[0][1][6]=1; dp[0][1][12]=1; dp[0][1][9]=1;
	dp[0][2][3]=1; dp[0][2][5]=1; dp[0][2][9]=1;
	dp[0][2][6]=1; dp[0][2][10]=1; dp[0][2][12]=1;
	dp[0][2][14]=2; dp[0][2][13]=2; dp[0][2][11]=2; dp[0][2][7]=2; dp[0][2][15]=2;
	dp[0][3][14]=1; dp[0][3][13]=1; dp[0][3][11]=1; dp[0][3][7]=1; dp[0][3][15]=4;
	dp[0][4][15]=1;
	rep(h,1,n)
		rep(c,0,m)
			rep(mask,0,15)
				rep(k,1,all[mask])
					if (c>=cs[mask][k][0])
						su(dp[h][c][mask],LL(dp[h-1][c-cs[mask][k][0]][cs[mask][k][1]])*cs[mask][k][2]%MD);

	int s=0;
	rep(mask,0,15) su(s,dp[n][m][mask]);
	rep(i,1,m) s=LL(s)*i%MD;
	printf("%d\n",s);
}

int main()
{
	ios::sync_with_stdio(true);
	#ifndef ONLINE_JUDGE
		freopen("336E.in","r",stdin);
	#endif
	lemon();
	return 0;
}

#include <iostream>
#include <sstream>
#include <fstream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <set>
#include <map>
#include <algorithm>
#include <functional>
#include <utility>
#include <bitset>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <cstdio>

using namespace std;

#define REP(i,n) for((i)=0;(i)<(int)(n);(i)++)
#define snuke(c,itr) for(__typeof((c).begin()) itr=(c).begin();itr!=(c).end();itr++)

typedef long long ll;
#define MOD 1000000007ll

vector <pair <int, int> > p; // in, out
vector <int> q; // in
int cnt[(1<<4)][(1<<4)][20]; // in, out, tri
int cnt2[(1<<4)][20]; // in, tri

#define two(x) (1<<(x))

void dfs(int pos, int in, int out, int tri){
    if(pos == p.size()){
        int mask=0,i;
        REP(i,12) if(out&(1<<i)) mask |= two(i/3);
        REP(i,16) if((mask&i) == mask) cnt[in][i][tri]++;
        return;
    }
    dfs(pos+1, in, out, tri);
    int in2 = p[pos].first, out2 = p[pos].second;
    if((in&in2) == 0 && (out&out2) == 0) dfs(pos+1, (in|in2), (out|out2), tri+1);
}

void dfs2(int pos, int in, int tri){
    if(pos == q.size()){
        cnt2[in][tri]++;
        return;
    }
    dfs2(pos+1, in, tri);
    int in2 = q[pos];
    if((in&in2) == 0) dfs2(pos+1, (in|in2), tri+1);
}

ll dp[210][210][16];

ll func(int level, int tri, int mask){
    int i,ans=0;

    if(dp[level][tri][mask] != -1) return dp[level][tri][mask];

    if(level == 0){
        if(tri < 20) REP(i,16) if((mask&i) == i) ans += cnt2[i][tri];
        return dp[level][tri][mask] = ans;
    }

    int in = mask;
    while(1){
        REP(i,13) if(i <= tri && cnt[in][mask][i] > 0){
            ll tmp = func(level-1, tri-i, (mask^in));
            ans = (ans + tmp * cnt[in][mask][i]) % MOD;
        }
        if(in == 0) break;
        in = ((in - 1) & mask);
    }

    return dp[level][tri][mask] = ans;
}

int main(void){
    int i,j,k;

    REP(i,12) p.push_back(make_pair(0, two(i)));
    REP(i,4) p.push_back(make_pair(0, two(3*i+2) + two((3*i+3)%12)));
    REP(i,4) p.push_back(make_pair(two(i), two(i*3) * 7));
    REP(i,4) p.push_back(make_pair(two(i) + two((i+1)%4), two(i*3) * 7 + two((i+1)%4*3) * 7));
    dfs(0, 0, 0, 0);

    REP(i,4) q.push_back(two(i));
    REP(i,4) q.push_back(two(i) + two((i+1)%4));
    dfs2(0, 0, 0);

    int N,K;
    cin >> N >> K;
    REP(i,N+1) REP(j,K+1) REP(k,16) dp[i][j][k] = -1;
    ll ans = func(N, K, 15);
    for(i=1;i<=K;i++) ans = ans * i % MOD;
    cout << ans << endl;

    return 0;
}

#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<map>
#include<ctime>
#include<set>
#include<queue>
#include<cmath>
#include<vector>
#include<bitset>
#include<functional>
#define x first
#define y second
#define mp make_pair
#define pb push_back
#define REP(i,l,r) for((i)=(l);(i)<=(r);++(i))
#define REP2(i,l,r) for((i)=(l);(i)!=(r);++(i))
using namespace std;

typedef long long LL;
typedef double ld;

const int MAX=201;
const int Mod=(int)1e9+7;

int n,k;

int f[MAX][1<<4][MAX];
int p[MAX];
LL C[MAX][MAX];

void work(int* p,int can,int must)
{
	int i,j;
	LL *CC=C[can];
	for(i=k;i>=0;--i)
	{
		LL np=p[i];
		if(must)
			np=0;
		REP(j,1,can)
			if(i>=j)
				np=np+p[i-j]*CC[j];
		p[i]=np%Mod;
	}
}

void update(int S,int *f,int nf[1<<4][MAX])
{
	int i;
	REP2(i,0,1<<4)
	{
		int nS=S,j,delta=0;
		REP2(j,0,4)
			if((i>>j)&1)
			{
				nS|=(1<<j);
				nS|=(1<<((j+3)%4));
				delta+=1;
			}
		int pS;
		REP2(pS,0,1<<4)
			if((pS&nS)==nS)
			{
				memset(p,0,sizeof p);
				REP(j,delta,k)
					p[j]=f[j-delta];
				REP2(j,0,4)
				{
					int s1=((i>>j)&1);
					int s2=(((i>>((j+1)%4)))&1);
					int can=3-s1-s2;
					int must=!s1 && !s2 && ((pS>>j)&1) && !((S>>j)&1);
					if((pS>>j)&1)
						work(p,can,must);
				}
				REP(j,0,k)
					nf[pS][j]=(nf[pS][j]+p[j]) % Mod;
			}
	}
}

void update2(int S,int* f,int nf[1<<4][MAX])
{
	int i,j;
	REP2(i,1,1<<4)
		if((S&i)==0)
		{
			int a=(i>>0)&1;
			int b=(i>>1)&1;
			int c=(i>>2)&1;
			int d=(i>>3)&1;
			int num=a+b+c+d;
			if(!num)
				continue;
			REP(j,0,k)
				p[j]=f[j];
			LL one=(a && b) +( b && c) + ( c&& d ) + ( d && a );
			LL two=(num==4)*2;
			for(j=k;j>=0;--j)
			{
				p[j]=0;
				if(j>=num)
					p[j]=(p[j]+p[j-num]) % Mod;
				if(j>=num-1)
					p[j]=(p[j]+p[j-(num-1)]*one) % Mod;
				if(j>=num-2)
					p[j]=(p[j]+p[j-(num-2)]*two) % Mod;
			}
			REP(j,0,k)
				nf[S|i][j]=(nf[S|i][j]+p[j]) % Mod;
		}
}

int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);freopen("output.txt","w",stdout);
#endif
	int i,j;
	cin>>n>>k;
	int p=k;
	C[0][0]=1;
	REP2(i,1,MAX)
	{
		C[i][0]=1;
		REP(j,1,i)
			C[i][j]=(C[i-1][j]+C[i-1][j-1]) % Mod;
	}
	f[0][0][0]=1;
	for(i=(1<<4)-1;i>=0;--i)
		update2(i,f[0][i],f[0]);
	REP(i,1,n)
	{
		REP2(j,0,1<<4)
			update(j,f[i-1][j],f[i]);
		for(j=(1<<4)-1;j>=0;--j)
			update2(j,f[i][j],f[i]);
	}
	LL ans=0;
	REP2(j,0,1<<4)
		ans=(ans+f[n][j][k]) % Mod;
	for(;p;p--)
		ans=ans*p%Mod;
	cout<<ans<<endl;
	return 0;
}

#include <cmath>
#include <algorithm>
#include <vector>
#include <iostream>
#include <cstdio>
#include <set>
#include <queue>
#include <map>
#include <string>
#include <cstring>
#include <ctime>
using namespace std;
#define For(i,a,b) for(int i=a;i<=b;i++)
#define Ford(i,a,b) for(int i=a;i>=b;i--)
#define Rep(i,c) for((type of c.begin()) i;i!=c.end();i++)
#define pb push_back
#define mp make_pair
#define fi first
#define se second
#define sr(x) (int)x.size()
#define modul 1000000007
#define nmax 210
#define BUG(x) {cout << #x << " = " << x << endl;}
#define PR(x,a,b) {cout << #x << " = "; For(_,a,b) cout << x[_] << ' '; cout << endl;}
#define fillchar(x,a,b,delta) For(_,a,b) x[_]=delta;
#define Bit(s,i) (s&(1<<i))
#define Two(x) (1<<x)
#define pii pair<int,int>
#define ll long long
#define e 1e-6
#define pi acos(-1)
int n,k;
ll dp[nmax][nmax][6][3];
bool kq[nmax][nmax][6][3];
ll c[nmax][nmax];
int add(ll u,ll v) {
    return (u+v)%modul;
}
int mul(ll u,ll v) {
    return (u*v)%modul;
}
int h[5]={8,6,4,2,4};
int p[5]={4,2,1,0,0};
ll Cal(int n,int k,int cur,int type) {
    if (k==0) return 1;
    if (cur==5) return 0;
    if (kq[n][k][cur][type]) return dp[n][k][cur][type];
    ll ans=0;kq[n][k][cur][type]=true;
    if (type==0) {
        if (n==0) return 0;
        int x;
        if (cur==4) x=2;else x=4-cur;
        For(i,0,min(x,k)) ans=add(ans,mul(Cal(n-1,k-i,cur,2),c[x][i]));
    } else
    if (type==1) {
        if (n==0) return 0;
        int u=h[cur],v=p[cur];
   //     BUG(u);BUG(v);
        For(i,0,u) For(j,0,v) if (i+2*j<=u && i+j<=k)
          ans=add(ans,mul( Cal(n,k-i-j,cur,0),c[v][j]*c[u-2*j][i] ));
    } else {
        ans=add(ans,Cal(n,k,cur,1));
        if (cur==1) {
            if (k>=1) ans=add(ans,Cal(n,k-1,2,1)*2+Cal(n,k-1,4,1)+Cal(n,k-1,3,1)*2);
            if (k>=2) ans=add(ans,Cal(n,k-2,3,1)*3+Cal(n,k-2,5,1)*2);
            if (k>=3) ans=add(ans,Cal(n,k-3,5,1));
        } else
        if (cur==2) {
            if (k>=1) ans=add(ans,Cal(n,k-1,3,1)*2+Cal(n,k-1,5,1));
            if (k>=2) ans=add(ans,Cal(n,k-2,5,1));
        } else
        if (cur==3) ans=add(ans,Cal(n,k-1,5,1));
        else if (cur==4) {
            if (k>=1) ans=add(ans,Cal(n,k-1,3,1)*2);
            if (k>=2) ans=add(ans,Cal(n,k-2,5,1));
        } else {
            if (k>=1) ans=add(ans,Cal(n,k-1,1,1)*4+Cal(n,k-1,2,1)*4);
            if (k>=2) ans=add(ans,Cal(n,k-2,2,1)*4+Cal(n,k-2,4,1)*2+Cal(n,k-2,3,1)*8+Cal(n,k-2,5,1)*2);
            if (k>=3) ans=add(ans,Cal(n,k-3,3,1)*4+Cal(n,k-3,5,1)*4);
            if (k>=4) ans=add(ans,Cal(n,k-4,5,1));
        }
    }
    dp[n][k][cur][type]=ans;return ans;
}
int main()
{
   // freopen("codeforces.inp","r",stdin);
    scanf("%d%d",&n,&k);
    c[0][0]=1;
    For(i,1,10) For(j,0,i) if (j==0 || j==i) c[i][j]=1; else c[i][j]=add(c[i-1][j],c[i-1][j-1]);
  //  For(i,1,10) PR(c[i],0,i);
    ll res=Cal(n,k,0,2);
    For(i,1,k) res=(res*i)%modul;
    printf("%d\n",res);
    return 0;
}

#include <algorithm>
#include <iostream>
#include <sstream>
#include <string>
#include <vector>
#include <queue>
#include <set>
#include <map>
#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cmath>
#include <list>
#include <climits>
#include <cassert>
#include <ctime>
#include <cstring>
using namespace std;

#define PB push_back
#define MP make_pair
#define SZ(v) ((int)(v).size())
#define FOR(i,a,b) for(int i=(a);i<(b);++i)
#define REP(i,n) FOR(i,0,n)
#define FORE(i,a,b) for(int i=(a);i<=(b);++i)
#define REPE(i,n) FORE(i,0,n)
#define FORSZ(i,a,v) FOR(i,a,SZ(v))
#define REPSZ(i,v) REP(i,SZ(v))
typedef long long ll;

const int MOD=1000000007;
int size,ncolors;

int ntriangles[5],npairs[5];
int choose[13][13];
int ways[5][13];

ll dp[201][201][5];	//dp[size][need][state] = number of ways to choose 'need' triangles for a structure of size 'size' form the given state (state=0 -> two opposite empty quadrants / otherwise state is the number of consecutive empty quadrants)

void run(int casenr) {
	ntriangles[0]=6; npairs[0]=0;
	ntriangles[1]=3; npairs[1]=0;
	ntriangles[2]=6; npairs[2]=1;
	ntriangles[3]=9; npairs[3]=2;
	ntriangles[4]=12; npairs[4]=4;
	REPE(i,12) { choose[i][0]=choose[i][i]=1; FOR(j,1,i) choose[i][j]=choose[i-1][j-1]+choose[i-1][j]; }
	REP(state,5) REPE(k,ntriangles[state]) { ways[state][k]=0; REPE(x,npairs[state]) if(x<=k&&ntriangles[state]-2*x>=k-x) ways[state][k]+=choose[npairs[state]][x]*choose[ntriangles[state]-2*x][k-x]; }

	scanf("%d%d",&size,&ncolors);

	memset(dp,0,sizeof(dp));
	REPE(k,2) dp[0][k][0]+=choose[2][k];
	REPE(k,1) dp[0][k][1]+=choose[1][k];
	REPE(k,2) dp[0][k][2]+=choose[2][k]; dp[0][1][2]++;
	REPE(k,3) dp[0][k][3]+=choose[3][k]; dp[0][1][3]+=2; dp[0][2][3]+=2;
	REPE(k,4) dp[0][k][4]+=choose[4][k]; dp[0][1][4]+=4; dp[0][2][4]+=8+2; dp[0][3][4]+=4;
	FORE(i,1,size) REPE(j,ncolors) {
		// state=0
		if(j==2) ++dp[i][j][0]; // two single quadrants
		if(j>=1) REPE(k,min(3,j-1)) dp[i][j][0]+=2*dp[i-1][j-1-k][1]*ways[1][k]; // one single quadrant
		REPE(k,min(6,j)) dp[i][j][0]+=dp[i-1][j-k][0]*ways[0][k];
		// state=1
		if(j==1) ++dp[i][j][1]; // one single quadrant
		REPE(k,min(3,j)) dp[i][j][1]+=dp[i-1][j-k][1]*ways[1][k];
		// state=2
		if(j==1) ++dp[i][j][2]; // one double quadrant
		if(j==2) ++dp[i][j][2]; // two single quadrants
		if(j>=1) REPE(k,min(3,j-1)) dp[i][j][2]+=2*dp[i-1][j-1-k][1]*ways[1][k]; // one quadrant
		REPE(k,min(6,j)) dp[i][j][2]+=dp[i-1][j-k][2]*ways[2][k];
		// state=3
		if(j==2) dp[i][j][3]+=2; // one double and one single quadrant
		if(j==3) ++dp[i][j][3]; // three single quadrants
		if(j>=1) REPE(k,min(3,j-1)) dp[i][j][3]+=2*dp[i-1][j-1-k][1]*ways[1][k]; // one double quadrant
		if(j>=2) REPE(k,min(3,j-2)) dp[i][j][3]+=3*dp[i-1][j-2-k][1]*ways[1][k]; // two single quadrants
		if(j>=1) REPE(k,min(6,j-1)) dp[i][j][3]+=2*dp[i-1][j-1-k][2]*ways[2][k]; // a single quadrant (non-middle)
		if(j>=1) REPE(k,min(6,j-1)) dp[i][j][3]+=1*dp[i-1][j-1-k][0]*ways[0][k]; // a single quadrant (middle)
		REPE(k,min(9,j)) dp[i][j][3]+=dp[i-1][j-k][3]*ways[3][k];
		// state=4
		if(j==2) dp[i][j][4]+=2; // two double quadrants
		if(j==3) dp[i][j][4]+=4; // one double and two single quadrants
		if(j==4) ++dp[i][j][4]; // four single quadrants
		if(j>=2) REPE(k,min(3,j-2)) dp[i][j][4]+=8*dp[i-1][j-2-k][1]*ways[1][k]; // one double and one single quadrant
		if(j>=3) REPE(k,min(3,j-3)) dp[i][j][4]+=4*dp[i-1][j-3-k][1]*ways[1][k]; // three single quadrants
		if(j>=1) REPE(k,min(6,j-1)) dp[i][j][4]+=4*dp[i-1][j-1-k][2]*ways[2][k]; // one double quadrant
		if(j>=2) REPE(k,min(6,j-2)) dp[i][j][4]+=4*dp[i-1][j-2-k][2]*ways[2][k]; // two single quadrants (adjacent)
		if(j>=2) REPE(k,min(6,j-2)) dp[i][j][4]+=2*dp[i-1][j-2-k][0]*ways[0][k]; // two single quadrants (opposite)
		if(j>=1) REPE(k,min(9,j-1)) dp[i][j][4]+=4*dp[i-1][j-1-k][3]*ways[3][k]; // one single quadrant
		REPE(k,min(12,j)) dp[i][j][4]+=dp[i-1][j-k][4]*ways[4][k];
		REP(state,5) dp[i][j][state]%=MOD;
	}
	ll ret=dp[size][ncolors][4];
	FORE(i,1,ncolors) ret=ret*i%MOD;
	cout<<ret;
}

int main() {
//	int n; scanf("%d",&n); FORE(i,1,n) run(i);
	run(1);
	return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i,j,k[5],l;
    if(num==0) return 1;
    if(num<0 || mask==0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];
    /*
    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3
    */

    ll ret=0;
    FOR(ma,16) {
        if((mask & ma)!=ma) continue;

        //get whole block
        int bi=__builtin_popcount(ma);
        k[0]=k[1]=k[2]=k[3]=k[4]=0;
        k[bi]=1;
        if(bi==2 && (ma!=5) && (ma!=10)) k[1]++;
        if(bi==3) k[2]+=2;
        if(bi==4) k[2]+=2,k[3]+=4;

        // get boarder
        if(level>0) {
            int ma2=mask^ma;
            if(ma2==13 || ma2==11 || ma2==14) ma2=7;
            if(ma2==9 || ma2==6 || ma2==12) ma2=3;
            if(ma2==10) ma2=5;
            if(ma2==2 || ma2==4 || ma2==8) ma2=1;

            int x,y;
            FOR(l,5){
                if(k[l]==0) continue;
                if(num-l<0) continue;
                if(ma2==0) x=0,y=0;
                else if(ma2==1) x=3,y=0;
                else if(ma2==5) x=6,y=0;
                else if(ma2==3) x=6,y=1;
                else if(ma2==7) x=9,y=2;
                else if(ma2==15) x=12,y=4;
                FOR(i,y+1) FOR(j,x-i*2+1) ret += dodp(level-1,num-l-(i+j),ma2) * ((k[l]* C[y][i] * C[x-i*2][j])%mo);
            }
        }
        else {
            FOR(l,5) ret += (num==l) * k[l];
        }
    }

    return dpdp[level][num][mask]=(ret%=mo);
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MOD = 1000000007;

int N, K;
int P[202][202][6][2];
int dig[1 << 12], tot[6][15], totsec[4][6][15];
bool okn[6][1 << 12];

inline void add(int& x, long long y)
{
    x += y % MOD;
    if (x >= MOD) x -= MOD;
}

int getDP(int size, int trng, int state, bool period)
{
    if (trng < 0) return 0;
    if (trng == 0) return 1;
    if (state == 4) return 0;
    if (size == 0 && period) return 0;

    int& now = P[size][trng][state][period];

    if (now != -1) return now;
    now = 0;

    if (period == false)
    {
        if (state == 0)
        {
            add(now, getDP(size, trng, 0, true));
            add(now, 4LL * getDP(size, trng - 1, 1, true));
            add(now, 4LL * getDP(size, trng - 1, 2, true));
            add(now, 4LL * getDP(size, trng - 2, 2, true));
            add(now, 8LL * getDP(size, trng - 2, 3, true));
            add(now, 4LL * getDP(size, trng - 3, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, 4LL * getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 4, 4, true));
            add(now, 2LL * getDP(size, trng - 2, 5, true));
        }
        else if (state == 1)
        {
            add(now, getDP(size, trng, 1, true));
            add(now, 2LL * getDP(size, trng - 1, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, 3LL * getDP(size, trng - 2, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 1, 5, true));
        }
        else if (state == 2)
        {
            add(now, getDP(size, trng, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
        else if (state == 3)
        {
            add(now, getDP(size, trng, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
        }
        else if (state == 5)
        {
            add(now, getDP(size, trng, 5, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
    }
    else
    {
        add(now, getDP(size - 1, trng, state, false));
        if (state == 0)
        {
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, tot[i][j] * 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, tot[i][j] * 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, tot[i][j] * 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, tot[i][j] * 1LL * getDP(size - 1, trng - total, 0, false));
                }
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, totsec[0][i][j] * 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, totsec[0][i][j] * 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, totsec[0][i][j] * 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, totsec[0][i][j] * 1LL * getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 1)
        {
            for (int i = 1; i <= 3 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, tot[i][j] * 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 2) add(now, tot[i][j] * 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 3) add(now, tot[i][j] * 1LL * getDP(size - 1, trng - total, 1, false));
                }
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, totsec[1][i][j] * 2LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 2) add(now, totsec[1][i][j] * 1LL * getDP(size - 1, trng - total, 1, false));
                }
        }
        else if (state == 2)
        {
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, tot[i][j] * 2LL * getDP(size - 1, trng - total, 2, false));
                    else if (i == 2) add(now, tot[i][j] * 1LL * getDP(size - 1, trng - total, 2, false));
                }
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, totsec[2][i][j] * 1LL * getDP(size - 1, trng - total, 2, false));
                }
        }
        else if (state == 3)
        {
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, tot[i][j] * 1LL * getDP(size - 1, trng - total, 3, false));
                }
        }
        else if (state == 5)
        {
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j <= min(12, trng); ++j)
                {
                    int total = j;
                    if (i == 1) add(now, tot[i][j] * 2LL * getDP(size - 1, trng - total, 5, false));
                    else if (i == 2) add(now, tot[i][j] * 1LL * getDP(size - 1, trng - total, 5, false));
                }
        }
    }

    return now;
}

int main()
{
    dig[0] = 0;
    for (int i = 1; i < (1 << 12); ++i)
        dig[i] = dig[i & (i - 1)] + 1;

    for (int i = 1; i <= 4; ++i)
        for (int j = 0; j < (1 << (3 * i)); ++j)
        {
            bool ok = true;
            for (int k = 1; k <= i; ++k)
                if (((j >> ((k - 1) * 3)) & 7) == 0)
                    ok = false;

            if (ok)
                ++tot[i][dig[j]];
        }

    for (int i = 1; i <= 4; ++i)
        for (int j = 0; j < (1 << (3 * 4 - 2 * i)); ++j)
            ++totsec[0][i][dig[j] + i];
    for (int i = 1; i <= 2; ++i)
        for (int j = 0; j < (1 << (3 * 3 - 2 * i)); ++j)
            ++totsec[1][i][dig[j] + i];
    for (int i = 1; i <= 1; ++i)
        for (int j = 0; j < (1 << (3 * 2 - 2 * i)); ++j)
            ++totsec[2][i][dig[j] + i];

    cin >> N >> K;

    memset(P, -1, sizeof(P));

    int result = getDP(N, K, 0, false);
    for (int i = 1; i <= K; ++i)
        result = 1LL * result * i % MOD;

    cout << result << '\n';
}

#include <stdio.h>
#include <memory.h>

const int MOD = 1000000007, N = 205, K = 10;
int dp[N][N][5][3], C[K][K], con[5], get[5], fact = 1, n, k;

inline void add(int &v1, int v2) {
	v1 += v2;
	if (v1 >= MOD)
		v1 -= MOD;
}

inline int mul(int v1, int v2) {
	long long res = v1;
	res *= v2;
	return (res % MOD);
}

int calc(int level, int operations, int cur, int type) {
	int &ans = dp[level][operations][cur][type];
	if (ans != -1)
		return ans;
	ans = 0;
	if (type == 0) {
		int bits = get[cur];
		for(int i = 0; (i <= bits) && (i <= operations); i++)
			add(ans, mul(calc(level - 1, operations - i, cur, 2), C[bits][i]));
	}
	if (type == 1) {
		if (level == 0) {
			if (operations == 0)
				return ans = 1;
			else
				return ans = 0;
		}
		int bits = get[cur];
		bits <<= 1;
		int cons = con[cur];
		for(int i = 0; (i <= cons) && (i <= operations); i++)
			for(int j = 0; (j <= (bits - 2 * i)) && (j <= (operations - i)); j++)
				add(ans, mul(calc(level, operations - i - j, cur, 0), mul(C[cons][i], C[bits - 2 * i][j])));
	}
	if (type == 2) {
		add(ans, calc(level, operations, cur, 1));
		if (cur == 0) {
			if (operations >= 1) {
				add(ans, mul(calc(level, operations - 1, 1, 1), 4));
				add(ans, mul(calc(level, operations - 1, 2, 1), 4));
			}
			if (operations >= 2) {
				add(ans, mul(calc(level, operations - 2, 4, 1), 2));
				add(ans, mul(calc(level, operations - 2, 2, 1), 4));
				add(ans, mul(calc(level, operations - 2, 3, 1), 8));
				if (operations == 2)
					add(ans, 2);
			}
			if (operations >= 3) {
				add(ans, mul(calc(level, operations - 3, 3, 1), 4));
				if (operations == 3)
					add(ans, 4);
			}
			if (operations == 4)
				add(ans, 1);
		}
		if (cur == 1) {
			if (operations >= 1) {
				add(ans, calc(level, operations - 1, 4, 1));
				add(ans, mul(calc(level, operations - 1, 2, 1),2));
				add(ans, mul(calc(level, operations - 1, 3, 1),2));
			}
			if (operations >= 2) {
				if (operations == 2)
					add(ans, 2);
				add(ans, mul(calc(level, operations - 2, 3, 1), 3));
			}
			if (operations == 3)
				add(ans, 1);
		}
		if (cur == 2) {
			if (operations >= 1) {
				add(ans, mul(calc(level, operations - 1, 3, 1), 2));
				if (operations == 1)
					add(ans, 1);
			}
			if (operations == 2)
				add(ans, 1);
		}
		if (cur == 3 && operations == 1)
			add(ans, 1);
		if (cur == 4) {
			if (operations >= 1) add(ans, mul(calc(level, operations - 1, 3, 1), 2));
			if (operations == 2)
				add(ans, 1);
		}
	}
	return ans;
}

int main() {
	get[0] = 4; con[0] = 4;
	get[1] = 3; con[1] = 2;
	get[2] = 2; con[2] = 1;
	get[3] = 1; con[3] = 0;
	get[4] = 2; con[4] = 0;
	for(int i = 0; i < K; i++)  {
		C[i][0] = 1;
		for(int j = 1; j <= i; j++)
			add(C[i][j], C[i - 1][j]), add(C[i][j], C[i - 1][j - 1]);
	}
	memset(dp, -1, sizeof dp);
	scanf("%d %d", &n, &k);
	for(int i = 1; i <= k; i++)	fact = mul(fact, i);
	printf("%d\n", mul(fact,calc(n, k, 0, 2)));
}

#include <algorithm>
#include <iostream>
#include <climits>
#include <list>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <numeric>

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

const int MOD = 1e9+7;

inline int add(int x, int y) {
    return (x + y) % MOD;
}

inline int mul(int x, int y) {
    return (long long)x * y % MOD;
}

const int tri[5] = {4, 3, 2, 1, 2};    // # of remained triangles
const int con[5] = {4, 2, 1, 0, 0};    // # of pair triangles (Note that pair triangles can be colored with one operations.)

long long dp[201][201][5][3];
long long cmb[10][10];

long long solve(int n, int k, int mask, int type) {
    long long &ret = dp[n][k][mask][type];
    if (ret != -1)
        return ret;

    ret = 0;
    if (type == 0) {
        ret = add(ret, solve(n, k, mask, 1));

        if (mask == 0) {
           if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 1, 1), 4));
                ret = add(ret, mul(solve(n, k-1, 2, 1), 4));
            }
            if (k >= 2) {
                ret = add(ret, mul(solve(n, k-2, 2, 1), 4));
                ret = add(ret, mul(solve(n, k-2, 3, 1), 8));
                ret = add(ret, mul(solve(n, k-2, 4, 1), 2));
                if (k == 2)
                    ret = add(ret, 2);
            }
            if (k >= 3) {
                ret = add(ret, mul(solve(n, k-3, 3, 1), 4));
                if (k == 3)
                    ret = add(ret, 4);
            }
            if (k == 4)
                ret = add(ret, 1);
        }
        else if (mask == 1) {
            if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 2, 1), 2));
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
                ret = add(ret, mul(solve(n, k-1, 4, 1), 1));
            }
            if (k >= 2) {
                ret = add(ret, mul(solve(n, k-2, 3, 1), 3));
                if (k == 2)
                    ret = add(ret, 2);
            }
            if (k == 3)
                ret = add(ret, 1);
        }
        else if (mask == 2) {
            if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
                if (k == 1)
                    ret = add(ret, 1);
            }
            if (k == 2)
                ret = add(ret, 1);
        }
        else if (mask == 3) {
            if (k == 1)
                ret = add(ret, 1);
        }
        else {
            if (k >= 1)
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
            if (k == 2)
                ret = add(ret, 1);
        }
    } else if (type == 1) {
        if (n == 0) return ret = k == 0;
        int all = tri[mask] << 1;
        int cons = con[mask];
        for (int i = 0; i <= cons && i <= k; i++) {
            for (int j = 0; 2* i + j <= all && i + j <= k; j++) {
                ret = add(ret, mul(solve(n, k-i-j, mask, 2), mul(cmb[cons][i], cmb[all-2*i][j])));
            }
        }

    } else {
        int cnt = tri[mask];
        for (int i = 0; i <= cnt && i <= k; i++) {
            ret = add(ret, mul(solve(n-1, k-i, mask, 0), cmb[cnt][i]));
        }
    }

    return ret;
}

int main() {
    ios_base::sync_with_stdio(0);
    int n, k;
    cin >> n >> k;

    for (int i = 0; i < 10; i++) {
        cmb[i][0] = 1;
        for (int j = 1; j <= i; j++)
            cmb[i][j] = add(cmb[i-1][j-1], cmb[i-1][j]);
    }

    memset(dp, -1, sizeof(dp));
    long long ret = solve(n, k, 0, 0);
    for (int i = 1; i <= k; i++)
        ret = ret * i % MOD;
    cout << ret << endl;

    return 0;
}

#include <algorithm>
#include <iostream>
#include <climits>
#include <list>
#include <map>
#include <cmath>
#include <queue>
#include <set>
#include <sstream>
#include <stack>
#include <cstdio>
#include <string>
#include <cstring>
#include <vector>
#include <numeric>

using namespace std;

#define ALL(x) (x).begin(), (x).end()
#define EACH(itr,c) for(__typeof((c).begin()) itr=(c).begin(); itr!=(c).end(); itr++)
#define FOR(i,b,e) for (int i=(int)(b); i<(int)(e); i++)
#define MP(x,y) make_pair(x,y)
#define REP(i,n) for(int i=0; i<(int)(n); i++)

const int MOD = 1e9+7;

inline int add(int x, int y) {
    return (x + y) % MOD;
}

inline int mul(int x, int y) {
    return (long long)x * y % MOD;
}

const int tri[5] = {4, 3, 2, 1, 2};    // # of remained triangles
const int con[5] = {4, 2, 1, 0, 0};    // # of pair triangles (Note that pair triangles can be colored with one operations.)

long long dp[201][201][5][3];
long long cmb[10][10];

long long solve(int n, int k, int mask, int type) {
    long long &ret = dp[n][k][mask][type];
    if (ret != -1)
        return ret;

    ret = 0;
    if (type == 0) {    // draw some quaters
        ret = add(ret, solve(n, k, mask, 1));

        if (mask == 0) {
           if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 1, 1), 4));
                ret = add(ret, mul(solve(n, k-1, 2, 1), 4));
            }
            if (k >= 2) {
                ret = add(ret, mul(solve(n, k-2, 2, 1), 4));
                ret = add(ret, mul(solve(n, k-2, 3, 1), 8));
                ret = add(ret, mul(solve(n, k-2, 4, 1), 2));
                if (k == 2)
                    ret = add(ret, 2);
            }
            if (k >= 3) {
                ret = add(ret, mul(solve(n, k-3, 3, 1), 4));
                if (k == 3)
                    ret = add(ret, 4);
            }
            if (k == 4)
                ret = add(ret, 1);
        }
        else if (mask == 1) {
            if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 2, 1), 2));
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
                ret = add(ret, mul(solve(n, k-1, 4, 1), 1));
            }
            if (k >= 2) {
                ret = add(ret, mul(solve(n, k-2, 3, 1), 3));
                if (k == 2)
                    ret = add(ret, 2);
            }
            if (k == 3)
                ret = add(ret, 1);
        }
        else if (mask == 2) {
            if (k >= 1) {
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
                if (k == 1)
                    ret = add(ret, 1);
            }
            if (k == 2)
                ret = add(ret, 1);
        }
        else if (mask == 3) {
            if (k == 1)
                ret = add(ret, 1);
        }
        else {
            if (k >= 1)
                ret = add(ret, mul(solve(n, k-1, 3, 1), 2));
            if (k == 2)
                ret = add(ret, 1);
        }
    } else if (type == 1) {              // draw outer layer
        if (n == 0) return ret = k == 0;
        int all = tri[mask] << 1;
        int cons = con[mask];
        for (int i = 0; i <= cons && i <= k; i++) {
            for (int j = 0; 2* i + j <= all && i + j <= k; j++) {
                ret = add(ret, mul(solve(n, k-i-j, mask, 2), mul(cmb[cons][i], cmb[all-2*i][j])));
            }
        }
    } else {                           // draw inner layer
        int cnt = tri[mask];
        for (int i = 0; i <= cnt && i <= k; i++) {
            ret = add(ret, mul(solve(n-1, k-i, mask, 0), cmb[cnt][i]));
        }
    }

    return ret;
}

int main() {
    ios_base::sync_with_stdio(0);
    int n, k;
    cin >> n >> k;

    for (int i = 0; i < 10; i++) {
        cmb[i][0] = 1;
        for (int j = 1; j <= i; j++)
            cmb[i][j] = add(cmb[i-1][j-1], cmb[i-1][j]);
    }

    memset(dp, -1, sizeof(dp));
    long long ret = solve(n, k, 0, 0);
    for (int i = 1; i <= k; i++)
        ret = ret * i % MOD;
    cout << ret << endl;

    return 0;
}

#include <cmath>
#include <map>
#include <vector>
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cstring>
#include <set>
#include <bitset>
#include <memory.h>
#include <functional>
#include <queue>
#include <fstream>
#include <ctime>
#include <deque>
#include <utility>
#include <stack>
#include <sstream>
#include <list>
#include <cctype>
#include <numeric>
#include <iomanip>
using namespace std;
#define sqr(_) ((_)*(_))

typedef pair<int, int> Pii;
#define x first
#define y second
#define mp make_pair

typedef long long LL;

const LL MAXN = 200 + 10, MOD = 1000000007;

LL n, m, c[MAXN][MAXN], f[MAXN][MAXN][5];
bool vis[MAXN][MAXN][5];

LL DFS(LL n, LL m, LL d)
{
	if (vis[n][m][d])
		return f[n][m][d];
	if ((n * 3 - 2) * d < m)
		return 0;
	if (m == 0) return 1;
	if (m < 0) return 0;
	vis[n][m][d] = 1;
	LL &Tohka = f[n][m][d];
	for (LL i = 0; i <= m; ++i)
		for (LL j = 0; j <= d - (d != 4) && j <= i; ++j)
			Tohka = ((LL)Tohka + (LL)DFS(n - 1, m - i, d) * c[d * 3 - j * 2][i - j] * c[d - (d != 4)][j]) % MOD;
	if (d == 1)
		Tohka += (m == 1);
	if (d == 2)
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 1, d - 1) * 2) % MOD,
		Tohka += (m == 1) - (m == 2);
	if (d == 3)
	{
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 1, d - 1) * 2) % MOD;
		for (LL i = 0; i < m; ++i)
			Tohka = ((LL)Tohka + (LL)DFS(n, i, 1) * DFS(n, m - 1 - i, 1)) % MOD;
		Tohka = (Tohka - (LL)DFS(n, m - 2, 1) * 3 % MOD + MOD + (m == 3)) % MOD;
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 1, 1) * 2 - (m == 2) * 2) % MOD;
	}
	if (d == 4)
	{
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 1, d - 1) * 4 - (LL)DFS(n, m - 2, d - 2) * 4 % MOD + MOD) % MOD;
		for (LL i = 0; i < m - 1; ++i)
			Tohka = (Tohka - (LL)DFS(n, i, 1) * DFS(n, m - 2 - i, 1) * 2 % MOD + MOD) % MOD;
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 3, 1) * 4 % MOD + MOD - (m == 4) + (m == 3) * 4) % MOD;
		Tohka = ((LL)Tohka + (LL)DFS(n, m - 1, 2) * 4 - (LL)DFS(n, m - 2, 1) * 8 - (m == 2) * 2 + MOD * 8) % MOD;
	}
	return Tohka;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt", "r", stdin), freopen("output.txt", "w", stdout);
#endif
	for (LL i = 0; i < MAXN; ++i)
		for (LL j = 0; j <= i; ++j)
			c[i][j] = (j) ? (c[i - 1][j] + c[i - 1][j - 1]) % MOD : 1;
	cin >> n >> m;
	LL Tohka = DFS(n + 1, m, 4);
	for (LL i = 1; i <= m; ++i)
		Tohka = (LL)Tohka * i % MOD;
	cout << Tohka << endl;
	fclose(stdin);
	fclose(stdout);
	return 0;
}

#include <iostream>

using namespace std;

typedef long long int ll;

ll modulo=1000000007;

ll combi[10][10];

ll triangulo1(int n,int k);
ll triangulo2opuesto(int n,int k);
ll triangulo2(int n,int k);
ll triangulo3(int n,int k);
ll triangulo4(int n,int k);

ll cuadrado1(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=1 and kk<=k;kk++)
    mem=(mem+combi[1][kk]*triangulo1(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado2opuesto(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*triangulo2opuesto(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado2(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*triangulo2(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado3(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=3 and kk<=k;kk++)
    mem=(mem+combi[3][kk]*triangulo3(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado4(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=4 and kk<=k;kk++)
    mem=(mem+combi[4][kk]*triangulo4(n-1,k-kk))%modulo;
  return mem;
}

ll memtriangulo1[201][201];

ll triangulo1(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 1;
    return 0;
  }
  ll &mem=memtriangulo1[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*cuadrado1(n,k-kk))%modulo;
  if (k==1) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo2opuesto[201][201];

ll triangulo2opuesto(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 2;
    if (k==2) return 1;
    return 0;
  }
  ll &mem=memtriangulo2opuesto[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk=0;kk<=4 and kk<=k;kk++)
    mem=(mem+combi[4][kk]*cuadrado2opuesto(n,k-kk))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  if (k==2) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo2[201][201];

ll triangulo2(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 3;
    if (k==2) return 1;
    return 0;
  }
  ll &mem=memtriangulo2[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=1 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-kk1-kk2))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  if (k==1) mem=(mem+1)%modulo;
  if (k==2) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo3[201][201];

ll triangulo3(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 5;
    if (k==2) return 3+2;
    if (k==3) return 1;
    return 0;
  }
  ll &mem=memtriangulo3[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=2 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=6-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[2][kk1]*combi[6-2*kk1][kk2]*cuadrado3(n,k-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+2*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-1-kk1-kk2))%modulo;
  for (int kk=0;kk<=4 and kk+1<=k;kk++)
    mem=(mem+combi[4][kk]*cuadrado2opuesto(n,k-kk-1))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  for (int kk=0;kk<=2 and kk+2<=k;kk++)
    mem=(mem+3*combi[2][kk]*cuadrado1(n,k-kk-2))%modulo;
  if (k==2) mem=(mem+2)%modulo;
  if (k==3) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo4[201][201];

ll triangulo4(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 8;
    if (k==2) return 6+8+2;
    if (k==3) return 4+4;
    if (k==4) return 1;
    return 0;
  }
  ll &mem=memtriangulo4[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=4 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=8-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[4][kk1]*combi[8-2*kk1][kk2]*cuadrado4(n,k-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=2 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=6-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+4*combi[2][kk1]*combi[6-2*kk1][kk2]*cuadrado3(n,k-1-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-2;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-2-kk1;kk2++)
      mem=(mem+4*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-2-kk1-kk2))%modulo;
  for (int kk=0;kk<=4 and kk<=k-2;kk++)
    mem=(mem+2*combi[4][kk]*cuadrado2opuesto(n,k-2-kk))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+4*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-1-kk1-kk2))%modulo;
  for (int kk=0;kk<=2 and kk+2<=k;kk++)
    mem=(mem+8*combi[2][kk]*cuadrado1(n,k-kk-2))%modulo;
  for (int kk=0;kk<=2 and kk+3<=k;kk++)
    mem=(mem+4*combi[2][kk]*cuadrado1(n,k-kk-3))%modulo;
  if (k==2) mem=(mem+2)%modulo;
  if (k==3) mem=(mem+4)%modulo;
  if (k==4) mem=(mem+1)%modulo;
  return mem;
}

int main()
{
  {
    for (int n=0;n<10;n++)
      for (int k=0;k<=n;k++)
	if (k==0 or k==n) combi[n][k]=1;
	else combi[n][k]=(combi[n-1][k]+combi[n-1][k-1])%modulo;
  }
  for (int i=0;i<201;i++)
    for (int j=0;j<201;j++)
      memtriangulo1[i][j]=memtriangulo2opuesto[i][j]=
	memtriangulo2[i][j]=memtriangulo3[i][j]=memtriangulo4[i][j]=-1;
  int n,k;
  cin>>n>>k;
  ll sol=triangulo4(n,k);
  for (int i=1;i<=k;i++)
    sol=(sol*i)%modulo;
  cout<<sol<<endl;
}

/*
⣿⣿⣿⣿⣿⣿⡷⣯⢿⣿⣷⣻⢯⣿⡽⣻⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣇⠸⣿⣿⣆⠹⣿⣿⢾⣟⣯⣿⣿⣿⣿⣿⣿⣽⣻⣿⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣻⣽⡿⣿⣎⠙⣿⣞⣷⡌⢻⣟⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣿⣿⡄⠹⣿⣿⡆⠻⣿⣟⣯⡿⣽⡿⣿⣿⣿⣿⣽⡷⣯⣿⣿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣟⣷⣿⣿⣿⡀⠹⣟⣾⣟⣆⠹⣯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢠⡘⣿⣿⡄⠉⢿⣿⣽⡷⣿⣻⣿⣿⣿⣿⡝⣷⣯⢿⣿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣯⢿⣾⢿⣿⡄⢄⠘⢿⣞⡿⣧⡈⢷⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡇⢸⣧⠘⣿⣷⠈⣦⠙⢿⣽⣷⣻⣽⣿⣿⣿⣿⣌⢿⣯⢿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⣟⣯⣿⢿⣿⡆⢸⡷⡈⢻⡽⣷⡷⡄⠻⣽⣿⣿⡿⣿⣿⣿⣿⣿⣿⣷⣿⣿⣿⣿⣏⢰⣯⢷⠈⣿⡆⢹⢷⡌⠻⡾⢋⣱⣯⣿⣿⣿⣿⡆⢻⡿⣿⣿⣿
⣿⣿⣿⣿⣿⣿⡎⣿⢾⡿⣿⡆⢸⣽⢻⣄⠹⣷⣟⣿⣄⠹⣟⣿⣿⣟⣿⣿⣿⣿⣿⣿⣽⣿⣿⣿⡇⢸⣯⣟⣧⠘⣷⠈⡯⠛⢀⡐⢾⣟⣷⣻⣿⣿⣿⡿⡌⢿⣻⣿⣿
⣿⣿⣿⣿⣿⣿⣧⢸⡿⣟⣿⡇⢸⣯⣟⣮⢧⡈⢿⣞⡿⣦⠘⠏⣹⣿⣽⢿⣿⣿⣿⣿⣯⣿⣿⣿⡇⢸⣿⣿⣾⡆⠹⢀⣠⣾⣟⣷⡈⢿⣞⣯⢿⣿⣿⣿⢷⠘⣯⣿⣿
⣿⣿⣿⣿⣿⣿⣿⡈⣿⢿⣽⡇⠘⠛⠛⠛⠓⠓⠈⠛⠛⠟⠇⢀⢿⣻⣿⣯⢿⣿⣿⣿⣷⢿⣿⣿⠁⣾⣿⣿⣿⣧⡄⠇⣹⣿⣾⣯⣿⡄⠻⣽⣯⢿⣻⣿⣿⡇⢹⣾⣿
⣿⣿⣿⣿⣿⣿⣿⡇⢹⣿⡽⡇⢸⣿⣿⣿⣿⣿⣞⣆⠰⣶⣶⡄⢀⢻⡿⣯⣿⡽⣿⣿⣿⢯⣟⡿⢀⣿⣿⣿⣿⣿⣧⠐⣸⣿⣿⣷⣿⣿⣆⠹⣯⣿⣻⣿⣿⣿⢀⣿⢿
⣿⣿⣿⣿⣿⣿⣿⣿⠘⣯⡿⡇⢸⣿⣿⣿⣿⣿⣿⣿⣧⡈⢿⣳⠘⡄⠻⣿⢾⣽⣟⡿⣿⢯⣿⡇⢸⣿⣿⣿⣿⣿⣿⡀⢾⣿⣿⣿⣿⣿⣿⣆⠹⣾⣷⣻⣿⡿⡇⢸⣿
⣿⣿⣿⣿⣿⣿⣿⣿⡇⢹⣿⠇⢸⣿⣿⣿⣿⣿⣿⣿⣿⣷⣄⠻⡇⢹⣆⠹⣟⣾⣽⣻⣟⣿⣽⠁⣾⣿⣿⣿⣿⣿⣿⣇⣿⣿⠿⠛⠛⠉⠙⠋⢀⠁⢘⣯⣿⣿⣧⠘⣿
⣿⣿⣿⣿⣿⣿⣿⣿⣿⡈⣿⡃⢼⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣦⡙⠌⣿⣆⠘⣿⣞⡿⣞⡿⡞⢠⣿⣿⣿⣿⣿⡿⠛⠉⠁⢀⣀⣠⣤⣤⣶⣶⣶⡆⢻⣽⣞⡿⣷⠈⣿
⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⠘⠁⠉⠉⠉⠉⠉⠉⠉⠉⠉⠙⠛⠛⢿⣄⢻⣿⣧⠘⢯⣟⡿⣽⠁⣾⣿⣿⣿⣿⣿⡃⢀⢀⠘⠛⠿⢿⣻⣟⣯⣽⣻⣵⡀⢿⣯⣟⣿⢀⣿
⣿⣿⣿⣟⣿⣿⣿⣿⣶⣶⡆⢀⣿⣾⣿⣾⣷⣿⣶⠿⠚⠉⢀⢀⣤⣿⣷⣿⣿⣷⡈⢿⣻⢃⣼⣿⣿⣿⣿⣻⣿⣿⣿⡶⣦⣤⣄⣀⡀⠉⠛⠛⠷⣯⣳⠈⣾⡽⣾⢀⣿
⣿⢿⣿⣿⣻⣿⣿⣿⣿⣿⡿⠐⣿⣿⣿⣿⠿⠋⠁⢀⢀⣤⣾⣿⣿⣿⣿⣿⣿⣿⣿⣌⣥⣾⡿⣿⣿⣷⣿⣿⢿⣷⣿⣿⣟⣾⣽⣳⢯⣟⣶⣦⣤⡾⣟⣦⠘⣿⢾⡁⢺
⣿⣻⣿⣿⡷⣿⣿⣿⣿⣿⡗⣦⠸⡿⠋⠁⢀⢀⣠⣴⢿⣿⣽⣻⢽⣾⣟⣷⣿⣟⣿⣿⣿⣳⠿⣵⣧⣼⣿⣿⣿⣿⣿⣾⣿⣿⣿⣿⣿⣽⣳⣯⣿⣿⣿⣽⢀⢷⣻⠄⠘
⣿⢷⣻⣿⣿⣷⣻⣿⣿⣿⡷⠛⣁⢀⣀⣤⣶⣿⣛⡿⣿⣮⣽⡻⣿⣮⣽⣻⢯⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣯⢀⢸⣿⢀⡆
⠸⣟⣯⣿⣿⣷⢿⣽⣿⣿⣷⣿⣷⣆⠹⣿⣶⣯⠿⣿⣶⣟⣻⢿⣷⣽⣻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⢀⣯⣟⢀⡇
⣇⠹⣟⣾⣻⣿⣿⢾⡽⣿⣿⣿⣿⣿⣆⢹⣶⣿⣻⣷⣯⣟⣿⣿⣽⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⢀⡿⡇⢸⡇
⣿⣆⠹⣷⡻⣽⣿⣯⢿⣽⣻⣿⣿⣿⣿⣆⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠇⢸⣿⠇⣼⡇
⡙⠾⣆⠹⣿⣦⠛⣿⢯⣷⢿⡽⣿⣿⣿⣿⣆⠻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠃⠎⢸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠏⢀⣿⣾⣣⡿⡇
⣿⣷⡌⢦⠙⣿⣿⣌⠻⣽⢯⣿⣽⣻⣿⣿⣿⣧⠩⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡏⢰⢣⠘⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠃⢀⢀⢿⣞⣷⢿⡇
⣿⣽⣆⠹⣧⠘⣿⣿⡷⣌⠙⢷⣯⡷⣟⣿⣿⣿⣷⡀⡹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣷⣈⠃⣸⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠟⢀⣴⡧⢀⠸⣿⡽⣿⢀
⢻⣽⣿⡄⢻⣷⡈⢿⣿⣿⢧⢀⠙⢿⣻⡾⣽⣻⣿⣿⣄⠌⢿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠛⢁⣰⣾⣟⡿⢀⡄⢿⣟⣿⢀
⡄⢿⣿⣷⢀⠹⣟⣆⠻⣿⣿⣆⢀⣀⠉⠻⣿⡽⣯⣿⣿⣷⣈⢻⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⢀⣠⠘⣯⣷⣿⡟⢀⢆⠸⣿⡟⢸
⣷⡈⢿⣿⣇⢱⡘⢿⣷⣬⣙⠿⣧⠘⣆⢀⠈⠻⣷⣟⣾⢿⣿⣆⠹⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⡿⠋⣠⡞⢡⣿⢀⣿⣿⣿⠇⡄⢸⡄⢻⡇⣼
⣿⣷⡈⢿⣿⡆⢣⡀⠙⢾⣟⣿⣿⣷⡈⠂⠘⣦⡈⠿⣯⣿⢾⣿⣆⠙⠻⠿⠿⠿⠿⡿⣿⣿⣿⣿⣿⣿⣿⣿⣿⠿⠛⢋⣠⣾⡟⢠⣿⣿⢀⣿⣿⡟⢠⣿⢈⣧⠘⢠⣿
⣿⣿⣿⣄⠻⣿⡄⢳⡄⢆⡙⠾⣽⣿⣿⣆⡀⢹⡷⣄⠙⢿⣿⡾⣿⣆⢀⡀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⢀⣀⣠⣴⡿⣯⠏⣠⣿⣿⡏⢸⣿⡿⢁⣿⣿⢀⣿⠆⢸⣿
⣿⣿⣿⣿⣦⡙⣿⣆⢻⡌⢿⣶⢤⣉⣙⣿⣷⡀⠙⠽⠷⠄⠹⣿⣟⣿⣆⢙⣋⣤⣤⣤⣄⣀⢀⢀⢀⢀⣾⣿⣟⡷⣯⡿⢃⣼⣿⣿⣿⠇⣼⡟⣡⣿⣿⣿⢀⡿⢠⠈⣿
⣿⣿⣿⣿⣿⣷⣮⣿⣿⣿⡌⠁⢤⣤⣤⣤⣬⣭⣴⣶⣶⣶⣆⠈⢻⣿⣿⣆⢻⣿⣿⣿⣿⣿⣿⣷⣶⣤⣌⣉⡘⠛⠻⠶⣿⣿⣿⣿⡟⣰⣫⣴⣿⣿⣿⣿⠄⣷⣿⣿⣿
*/

#include <bits/stdc++.h>

using namespace std;

#define x first
#define y second
#define mp make_pair
#define pb push_back
#define sqr(a) ((a) * (a))
#define sz(a) int(a.size())
#define all(a) a.begin(), a.end()
#define forn(i, n) for(int i = 0; i < int(n); i++)
#define fore(i, l, r) for(int i = int(l); i < int(r); i++)

typedef long long li;
typedef long double ld;
typedef pair<int, int> pt;

template <class A, class B> ostream& operator << (ostream& out, const pair<A, B> &a) {
	return out << "(" << a.x << ", " << a.y << ")";
}

template <class A> ostream& operator << (ostream& out, const vector<A> &v) {
	out << "[";
	forn(i, sz(v)) {
		if(i) out << ", ";
		out << v[i];
	}
	return out << "]";
}

mt19937 rnd(time(NULL));

const int INF = int(1e9);
const li INF64 = li(1e18);
const int MOD = INF + 7;
const ld EPS = 1e-9;
const ld PI = acos(-1.0);

const int N = 200 + 7;

int n, k;

bool read () {
	if (scanf("%d%d", &n, &k) != 2)
		return false;
	return true;
}

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

int mul(int a, int b){
	return a * li(b) % MOD;
}

int dp[N][N][16];
int mv[16][16][13];

int calc(int n, int k, int mask){
	if (dp[n][k][mask] != -1)
		return dp[n][k][mask];
	int& d = dp[n][k][mask];
	d = 0;
	for (int nmask = mask; nmask > 0; nmask = mask & (nmask - 1)) forn(dl, min(12, k) + 1)
		d = add(d, mul(mv[mask][nmask][dl], calc(n - 1, k - dl, nmask)));
	forn(dl, min(12, k) + 1)
		d = add(d, mul(mv[mask][0][dl], calc(n - 1, k - dl, 0)));
	return d;
}

void init(){
	forn(i, k + 1) forn(j, 16) dp[0][i][j] = 0;
	forn(mask, 16){
		forn(t, 1 << 8){
			bool ok = true;
			forn(i, 4) if (((t >> i) & 1) && !((mask >> i) & 1))
				ok = false;
			if (!ok) continue;
			forn(i, 4) if (((t >> (i + 4)) & 1) && (!((mask >> i) & 1) || !((mask >> ((i + 1) % 4)) & 1)))
				ok = false;
			if (!ok) continue;
			forn(i, 4) if (((t >> i) & 1) && (((t >> (i + 4)) & 1) || ((t >> ((i + 3) % 4 + 4)) & 1)))
				ok = false;
			if (!ok) continue;
			forn(i, 4) if (((t >> (i + 4)) & 1) && ((t >> ((i + 1) % 4 + 4)) & 1))
				ok = false;
			if (!ok) continue;
			++dp[0][__builtin_popcount(t)][mask];
		}
	}
	static int help[16][13];
	memset(help, 0, sizeof(help));
	forn(mask, 16){
		forn(t, 1 << 16){
			bool ok = true;
			int rmask = 0;
			forn(i, 4) if ((t >> (i * 3)) & 7)
				rmask |= (1 << i);
			forn(i, 4) if ((t >> (i + 12)) & 1){
				rmask |= (1 << i);
				rmask |= (1 << ((i + 1) % 4));
			}
			if (rmask != mask) continue;
			forn(i, 4) if (((t >> (i + 12)) & 1) && (((t >> (i * 3 + 2)) & 1) || ((t >> ((i * 3 + 3) % 12)) & 1)))
				ok = false;
			if (!ok) continue;
			++help[mask][__builtin_popcount(t)];
		}
	}
	memset(mv, 0, sizeof(mv));
	forn(mask, 16){
		forn(t, 1 << 12){
			bool ok = true;
			forn(i, 4) if (((t >> i) & 1) && !((mask >> i) & 1))
				ok = false;
			if (!ok) continue;
			int nmask = mask;
			forn(i, 4) if ((t >> (i + 4)) & 1){
				if (!((mask >> i) & 1))
					ok = false;
				else
					nmask ^= (1 << i);
			}
			if (!ok) continue;
			forn(i, 4) if ((t >> (i + 8)) & 1){
				if (!((mask >> i) & 1) || !((mask >> ((i + 1) % 4)) & 1))
					ok = false;
				else{
					nmask ^= (1 << i);
					nmask ^= (1 << ((i + 1) % 4));
				}
			}
			if (!ok) continue;
			forn(i, 4) if (((t >> i) & 1) && (((t >> (i + 4)) & 1) || ((t >> (i + 8)) & 1) || ((t >> ((i + 3) % 4 + 8)) & 1)))
				ok = false;
			if (!ok) continue;
			forn(i, 4) if (((t >> (i + 4)) & 1) && (((t >> (i + 8)) & 1) || ((t >> ((i + 3) % 4 + 8)) & 1)))
				ok = false;
			if (!ok) continue;
			forn(i, 4) if (((t >> (i + 8)) & 1) && ((t >> ((i + 1) % 4 + 8)) & 1))
				ok = false;
			if (!ok) continue;
			//forn(i, 12) cerr << ((t >> i) & 1);
			//cerr << endl;
			int cnt1 = t & 15;
			int cnt2 = __builtin_popcount(t >> 4);
			forn(i, 13) if (i >= cnt2)
				mv[mask][nmask][i] = add(mv[mask][nmask][i], help[cnt1][i - cnt2]);
		}
	}
}

void solve(){
	memset(dp, -1, sizeof(dp));
	init();
	int ans = calc(n, k, 15);
	fore(i, 1, k + 1) ans = mul(ans, i);
	printf("%d\n", ans);
}

int main() {
#ifdef _DEBUG
	freopen("input.txt", "r", stdin);
//	freopen("output.txt", "w", stdout);

	int tt = clock();

#endif

	cerr.precision(15);
	cout.precision(15);
	cerr << fixed;
	cout << fixed;

	while(read()) {
		solve();

#ifdef _DEBUG
	cerr << "TIME = " << clock() - tt << endl;
	tt = clock();
#endif

	}
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define sz(x) ((int)(x).size())
#define rep(i,l,r) for(int i=(l);i<(r);++i)
//------
const int N = 2e2 + 7;
const int MOD = 1e9 + 7;
int n, k, C[10][10], dp[N][N][5][3];
inline void inc(int &x, int y) {
	x += y;
	if (x >= MOD)
		x -= MOD;
}
inline int mul(int x, int y) {
	return 1ll * x * y % MOD;
}
const int tri[] = { 4, 3, 2, 1, 2 };
const int cor[] = { 4, 2, 1, 0, 0 };
int dfs(int lvl, int op, int qua, int type) {
	int &ret = dp[lvl][op][qua][type];
	if (~ret)
		return ret;
	ret = 0;
	if (type == 0) {
		int _tri = tri[qua];
		for (int i = 0; i <= min(_tri, op); ++i)
			inc(ret, mul(dfs(lvl - 1, op - i, qua, 2), C[_tri][i]));
	}
	if (type == 1) {
		if (lvl == 0)
			return ret = (op == 0);
		int _tri = tri[qua] << 1, _cor = cor[qua];
		for (int i = 0; i <= min(_cor, op); ++i)
			for (int j = 0; j <= min(op - i, _tri - (i << 1)); ++j)
				inc(ret, mul(dfs(lvl, op - i - j, qua, 0),
					mul(C[_cor][i], C[_tri - (i << 1)][j])));
	}
	if (type == 2) {
		inc(ret, dfs(lvl, op, qua, 1));
		if (qua == 0) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 1, 1), 4));
				inc(ret, mul(dfs(lvl, op - 1, 2, 1), 4));
			}
			if (op >= 2) {
				inc(ret, mul(dfs(lvl, op - 2, 2, 1), 4));
				inc(ret, mul(dfs(lvl, op - 2, 3, 1), 8));
				inc(ret, mul(dfs(lvl, op - 2, 4, 1), 2));
				if (op == 2)
					inc(ret, 2);
			}
			if (op >= 3) {
				inc(ret, mul(dfs(lvl, op - 3, 3, 1), 4));
				if (op == 3)
					inc(ret, 4);
			}
			if (op == 4)
				inc(ret, 1);
		}
		if (qua == 1) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 2, 1), 2));
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
				inc(ret, dfs(lvl, op - 1, 4, 1));
			}
			if (op >= 2) {
				inc(ret, mul(dfs(lvl, op - 2, 3, 1), 3));
				if (op == 2)
					inc(ret, 2);
			}
			if (op == 3)
				inc(ret, 1);
		}
		if (qua == 2) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
				if (op == 1)
					inc(ret, 1);
			}
			if (op == 2)
				inc(ret, 1);
		}
		if (qua == 3 && op == 1)
			inc(ret, 1);
		if (qua == 4) {
			if (op >= 1)
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
			if (op == 2)
				inc(ret, 1);
		}
	}
	return ret;
}
int fac(int n) {
	int ret = 1;
	rep(i, 2, n + 1)
		ret = 1ll * ret * i % MOD;
	return ret;
}
int main() {
	rep(i, 0, 10) {
		C[i][0] = C[i][i] = 1;
		rep(j, 1, i)
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
	}
	scanf("%d%d", &n, &k);
	memset(dp, -1, sizeof(dp));
	int ans = mul(dfs(n, k, 0, 2), fac(k));
	printf("%d", ans);
	return 0;
}

#include <iostream>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <complex>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int P = 1e9 + 7 , N = 205 , S = 6;
vi pat;

void pp(int &x,int d){
    x += d;
    if(x >= P) x -= P;
}

int dp[1 << 16][13];
void Dp(int s){
    memset(dp,0,sizeof(dp));
    dp[s][0] = 1;
    for(auto mask : pat){
        for(int i=(1<<16)-1;i>=0;--i)
            for(int j=12;j>=0;--j)
                if(dp[i][j] && (i&mask) == 0)
                    pp(dp[i | mask][j+1] , dp[i][j]);
    }
}

int n , K , f[N][S] , g[N][S] , to[1 << 16];
const int MaxT = 200;
int u[MaxT] , v[MaxT] , add[MaxT] , way[MaxT] , _;
map<pair<pii,int> , int> Mp;
void load(int a,int b,int c,int d){
    u[_] = a , v[_] = b , add[_] = c , way[_++] = d;
}
void Prepare(){
    load(0 , 0 , 0 , 1);
    load(0 , 1 , 1 , 16);
    load(0 , 1 , 2 , 12);
    load(0 , 1 , 3 , 4);
    load(0 , 2 , 1 , 8);
    load(0 , 2 , 2 , 80);
    load(0 , 2 , 3 , 120);
    load(0 , 2 , 4 , 84);
    load(0 , 2 , 5 , 28);
    load(0 , 2 , 6 , 4);
    load(0 , 3 , 2 , 68);
    load(0 , 3 , 3 , 452);
    load(0 , 3 , 4 , 920);
    load(0 , 3 , 5 , 968);
    load(0 , 3 , 6 , 592);
    load(0 , 3 , 7 , 216);
    load(0 , 3 , 8 , 44);
    load(0 , 3 , 9 , 4);
    load(0 , 4 , 2 , 8);
    load(0 , 4 , 3 , 180);
    load(0 , 4 , 4 , 901);
    load(0 , 4 , 5 , 2088);
    load(0 , 4 , 6 , 2802);
    load(0 , 4 , 7 , 2384);
    load(0 , 4 , 8 , 1334);
    load(0 , 4 , 9 , 492);
    load(0 , 4 , 10 , 116);
    load(0 , 4 , 11 , 16);
    load(0 , 4 , 12 , 1);
    load(0 , 5 , 2 , 32);
    load(0 , 5 , 3 , 48);
    load(0 , 5 , 4 , 34);
    load(0 , 5 , 5 , 12);
    load(0 , 5 , 6 , 2);
    load(1 , 1 , 0 , 1);
    load(1 , 1 , 1 , 3);
    load(1 , 1 , 2 , 3);
    load(1 , 1 , 3 , 1);
    load(1 , 2 , 1 , 10);
    load(1 , 2 , 2 , 38);
    load(1 , 2 , 3 , 56);
    load(1 , 2 , 4 , 40);
    load(1 , 2 , 5 , 14);
    load(1 , 2 , 6 , 2);
    load(1 , 3 , 1 , 4);
    load(1 , 3 , 2 , 87);
    load(1 , 3 , 3 , 355);
    load(1 , 3 , 4 , 661);
    load(1 , 3 , 5 , 687);
    load(1 , 3 , 6 , 427);
    load(1 , 3 , 7 , 159);
    load(1 , 3 , 8 , 33);
    load(1 , 3 , 9 , 3);
    load(1 , 4 , 2 , 21);
    load(1 , 4 , 3 , 236);
    load(1 , 4 , 4 , 958);
    load(1 , 4 , 5 , 2058);
    load(1 , 4 , 6 , 2694);
    load(1 , 4 , 7 , 2288);
    load(1 , 4 , 8 , 1291);
    load(1 , 4 , 9 , 482);
    load(1 , 4 , 10 , 115);
    load(1 , 4 , 11 , 16);
    load(1 , 4 , 12 , 1);
    load(1 , 5 , 1 , 4);
    load(1 , 5 , 2 , 15);
    load(1 , 5 , 3 , 22);
    load(1 , 5 , 4 , 16);
    load(1 , 5 , 5 , 6);
    load(1 , 5 , 6 , 1);
    load(2 , 2 , 0 , 1);
    load(2 , 2 , 1 , 7);
    load(2 , 2 , 2 , 19);
    load(2 , 2 , 3 , 26);
    load(2 , 2 , 4 , 19);
    load(2 , 2 , 5 , 7);
    load(2 , 2 , 6 , 1);
    load(2 , 3 , 1 , 10);
    load(2 , 3 , 2 , 78);
    load(2 , 3 , 3 , 248);
    load(2 , 3 , 4 , 426);
    load(2 , 3 , 5 , 436);
    load(2 , 3 , 6 , 274);
    load(2 , 3 , 7 , 104);
    load(2 , 3 , 8 , 22);
    load(2 , 3 , 9 , 2);
    load(2 , 4 , 1 , 2);
    load(2 , 4 , 2 , 45);
    load(2 , 4 , 3 , 306);
    load(2 , 4 , 4 , 1030);
    load(2 , 4 , 5 , 2046);
    load(2 , 4 , 6 , 2601);
    load(2 , 4 , 7 , 2198);
    load(2 , 4 , 8 , 1249);
    load(2 , 4 , 9 , 472);
    load(2 , 4 , 10 , 114);
    load(2 , 4 , 11 , 16);
    load(2 , 4 , 12 , 1);
    load(3 , 3 , 0 , 1);
    load(3 , 3 , 1 , 11);
    load(3 , 3 , 2 , 51);
    load(3 , 3 , 3 , 131);
    load(3 , 3 , 4 , 206);
    load(3 , 3 , 5 , 206);
    load(3 , 3 , 6 , 131);
    load(3 , 3 , 7 , 51);
    load(3 , 3 , 8 , 11);
    load(3 , 3 , 9 , 1);
    load(3 , 4 , 1 , 6);
    load(3 , 4 , 2 , 72);
    load(3 , 4 , 3 , 372);
    load(3 , 4 , 4 , 1093);
    load(3 , 4 , 5 , 2032);
    load(3 , 4 , 6 , 2513);
    load(3 , 4 , 7 , 2112);
    load(3 , 4 , 8 , 1208);
    load(3 , 4 , 9 , 462);
    load(3 , 4 , 10 , 113);
    load(3 , 4 , 11 , 16);
    load(3 , 4 , 12 , 1);
    load(4 , 4 , 0 , 1);
    load(4 , 4 , 1 , 16);
    load(4 , 4 , 2 , 112);
    load(4 , 4 , 3 , 452);
    load(4 , 4 , 4 , 1168);
    load(4 , 4 , 5 , 2032);
    load(4 , 4 , 6 , 2438);
    load(4 , 4 , 7 , 2032);
    load(4 , 4 , 8 , 1168);
    load(4 , 4 , 9 , 452);
    load(4 , 4 , 10 , 112);
    load(4 , 4 , 11 , 16);
    load(4 , 4 , 12 , 1);
    load(5 , 3 , 1 , 12);
    load(5 , 3 , 2 , 84);
    load(5 , 3 , 3 , 252);
    load(5 , 3 , 4 , 422);
    load(5 , 3 , 5 , 430);
    load(5 , 3 , 6 , 272);
    load(5 , 3 , 7 , 104);
    load(5 , 3 , 8 , 22);
    load(5 , 3 , 9 , 2);
    load(5 , 4 , 2 , 36);
    load(5 , 4 , 3 , 288);
    load(5 , 4 , 4 , 1008);
    load(5 , 4 , 5 , 2028);
    load(5 , 4 , 6 , 2592);
    load(5 , 4 , 7 , 2196);
    load(5 , 4 , 8 , 1249);
    load(5 , 4 , 9 , 472);
    load(5 , 4 , 10 , 114);
    load(5 , 4 , 11 , 16);
    load(5 , 4 , 12 , 1);
    load(5 , 5 , 0 , 1);
    load(5 , 5 , 1 , 6);
    load(5 , 5 , 2 , 15);
    load(5 , 5 , 3 , 20);
    load(5 , 5 , 4 , 15);
    load(5 , 5 , 5 , 6);
    load(5 , 5 , 6 , 1);
    f[0][0] = 1;
    f[1][1] = 4 , f[1][2] = 4;
    f[2][2] = 4 , f[2][3] = 8;
    f[2][4] = 2 , f[2][5] = 2;
    f[3][3] = 4 , f[3][4] = 4;
    f[4][4] = 1;
    return ;
    vi tri;
    rep(i,0,4){
        int mask = 1 << 0 | 1 << 4 | 1 << 8 | 1 << 12;
        tri.pb(mask << i);
    }
    rep(i,0,1<<16) {
        rep(j,0,4) if(tri[j] & i) to[i] |= 1 << j;
        if(__builtin_popcount(to[i]) == 2)
            to[i] = (to[i] == 5 || to[i] == 10) ? 5 : 2;
        else to[i] = __builtin_popcount(to[i]);
    }
    rep(i,0,4) pat.pb(tri[i] | tri[(i+1)%4]) , pat.pb(tri[i]);
    Dp(0);
    rep(i,0,1<<16) rep(j,0,13) pp(f[j][to[i]] , dp[i][j]);
    //rep(i,0,12) rep(j,0,6) if(f[i][j]) cout << i << " " << j << " " << f[i][j] << endl;

    rep(i,4,16) pat.pb(1 << i);
    pat.pb(1 << 8 | 1 << 15);
    pat.pb(1 << 9 | 1 << 12);
    pat.pb(1 << 10| 1 << 13);
    pat.pb(1 << 11| 1 << 14);
    static bool vis[16];
    rep(i,0,16) if(!vis[to[i]]){
        Dp(i);
        vis[to[i]] = true;
        rep(j,0,1<<16) rep(k,0,13) if(dp[j][k])
            pp(Mp[mp(mp(to[i] , to[j]) , k)] , dp[j][k]);
    }
    for(auto e : Mp)
        u[_] = e.fi.fi.fi , v[_] = e.fi.fi.se , add[_] = e.fi.se , way[_++] = e.se;
    //rep(i,0,_) printf("load(%d , %d , %d , %d);\n",u[i],v[i],add[i],way[i]);
}

int main(){
    Prepare();
    int n , K;
    scanf("%d%d",&n,&K);
    rep(i,0,n){
        memset(g , 0 , sizeof(g));
        rep(j,0,K+1) rep(k,0,_) if(j + add[k] <= K)
            pp(g[j+add[k]][v[k]] , 1ll * f[j][u[k]] * way[k] % P);
        memcpy(f , g , sizeof(f));
    }
    int ans = 0;
    rep(k,0,S) pp(ans , f[K][k]);
    rep(i,1,K+1) ans = 1ll * ans * i % P;
    printf("%d\n",ans);
    return 0;
}

#include <iostream>
#include <cassert>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <cmath>
#include <ctime>
#include <queue>
#include <set>
#include <map>
#include <stack>
#include <string>
#include <bitset>
#include <vector>
#include <complex>
#include <algorithm>
using namespace std;
typedef long long ll;
typedef double db;
typedef pair<int,int> pii;
typedef vector<int> vi;
#define de(x) cout << #x << "=" << x << endl
#define rep(i,a,b) for(int i=a;i<(b);++i)
#define all(x) (x).begin(),(x).end()
#define sz(x) (int)(x).size()
#define mp make_pair
#define pb push_back
#define fi first
#define se second
const int P = 1e9 + 7 , N = 205 , S = 6;
vi pat;

void pp(int &x,int d){
    x += d;
    if(x >= P) x -= P;
}

int dp[1 << 16][13];
void Dp(int s){
    memset(dp,0,sizeof(dp));
    dp[s][0] = 1;
    for(auto mask : pat){
        for(int i=(1<<16)-1;i>=0;--i)
            for(int j=12;j>=0;--j)
                if(dp[i][j] && (i&mask) == 0)
                    pp(dp[i | mask][j+1] , dp[i][j]);
    }
}

int n , K , f[N][S] , g[N][S] , to[1 << 16];
const int MaxT = 200;
int u[MaxT] , v[MaxT] , add[MaxT] , way[MaxT] , _;
map<pair<pii,int> , int> Mp;
void Prepare(){
    vi tri;
    rep(i,0,4){
        int mask = 1 << 0 | 1 << 4 | 1 << 8 | 1 << 12;
        tri.pb(mask << i);
    }
    rep(i,0,1<<16) {
        rep(j,0,4) if(tri[j] & i) to[i] |= 1 << j;
        if(__builtin_popcount(to[i]) == 2)
            to[i] = (to[i] == 5 || to[i] == 10) ? 5 : 2;
        else to[i] = __builtin_popcount(to[i]);
    }
    rep(i,0,4) pat.pb(tri[i] | tri[(i+1)%4]) , pat.pb(tri[i]);
    Dp(0);
    rep(i,0,1<<16) rep(j,0,13) pp(f[j][to[i]] , dp[i][j]);
    rep(i,4,16) pat.pb(1 << i);
    pat.pb(1 << 8 | 1 << 15);
    pat.pb(1 << 9 | 1 << 12);
    pat.pb(1 << 10| 1 << 13);
    pat.pb(1 << 11| 1 << 14);
    static bool vis[16];
    rep(i,0,16) if(!vis[to[i]]){
        Dp(i);
        vis[to[i]] = true;
        rep(j,0,1<<16) rep(k,0,13) if(dp[j][k])
            pp(Mp[mp(mp(to[i] , to[j]) , k)] , dp[j][k]);
    }
    for(auto e : Mp)
        u[_] = e.fi.fi.fi , v[_] = e.fi.fi.se , add[_] = e.fi.se , way[_++] = e.se;
}

int main(){
    Prepare();
    int n , K;
    scanf("%d%d",&n,&K);
    rep(i,0,n){
        memset(g , 0 , sizeof(g));
        rep(j,0,K+1) rep(k,0,_) if(j + add[k] <= K)
            pp(g[j+add[k]][v[k]] , 1ll * f[j][u[k]] * way[k] % P);
        memcpy(f , g , sizeof(f));
    }
    int ans = 0;
    rep(k,0,S) pp(ans , f[K][k]);
    rep(i,1,K+1) ans = 1ll * ans * i % P;
    printf("%d\n",ans);
    return 0;
}

// by ξ
// program sky  :)

#include <cstdio>
#include <cstring>
#include <algorithm>

#define elif else if
#define For(i,l,r) for(int _r=r,i=l;i<=_r;++i)
#define rep(i,l,r) for(int _r=r,i=l;i<_r;++i)
#define dto(i,r,l) for(int _l=l,i=r;i>=_l;--i)

using namespace std;

const int mo=1e9+7;

int n,K,M,dp[2][201][16],he[55],binom[55][55],tr[55][55][201],kua[55],way[55][5];

struct Edge{
	int v,k,con,nxt;
}Ed[5000];

#define cnt(x) (__builtin_popcount(x))

inline void inc(int &x,int y){
	if((x+=y)>=mo)x-=mo;
}

inline void Add(int u,int v,int k,int con){
	Ed[++M]=(Edge){v,k,con,he[u]};he[u]=M;
}

int main(){
// say hello
	scanf("%d%d",&n,&K);

	For(i,0,22){
		*binom[i]=1;
		For(j,1,i)
			binom[i][j]=(binom[i-1][j-1]+binom[i-1][j])%mo;
	}
	int lim=1<<4;--lim;

	kua[0]=4;
	kua[1]=kua[2]=kua[4]=kua[8]=2;
	kua[3]=kua[6]=kua[9]=kua[12]=1;

	way[0][0]=1;
	way[1][1]=way[2][1]=way[4][1]=way[8][1]=1;
	way[5][2]=way[10][2]=1;
	way[3][1]=way[6][1]=way[9][1]=way[12][1]=1;
	way[3][2]=way[6][2]=way[9][2]=way[12][2]=1;
	way[7][3]=way[11][3]=way[13][3]=way[14][3]=1;
	way[7][2]=way[11][2]=way[13][2]=way[14][2]=2;
	way[15][4]=1;
	way[15][2]=2;
	way[15][3]=4;

	For(i,0,lim)
	For(j,0,lim)if((j&i)==0){
		int k=i|j;
		For(p,0,kua[k]){
			int _=(4-cnt(k))*3-p*2;
			For(q,0,_)
				For(cn,0,4)if(way[j][cn])
				inc(tr[i][k][cn+p+q],1ll*binom[kua[k]][p]*binom[_][q]%mo*way[j][cn]%mo);
		}
	}

	For(i,0,lim)dto(k,12,0)For(j,0,lim)
		if(tr[i][j][k])Add(i,j,k,tr[i][j][k]);

	dp[n+1&1][0][0]=1;

	dto(i,n+1,2){
		int p=i&1,q=p^1;
		memset(dp[q],0,sizeof dp[q]);
		For(k,0,K)
		For(mask,0,lim)if(dp[p][k][mask])
			for(int e=he[mask];e;e=Ed[e].nxt){
				int kk=k+Ed[e].k;
				if(kk>K)break;
				inc(dp[q][kk][Ed[e].v],1ll*dp[p][k][mask]*Ed[e].con%mo);
			}
	}

	dto(i,lim,0)
	For(j,0,lim)if(j>i && (i&j)==i)
	For(k,0,4)
	inc(way[j][k],way[i][k]);

	int res=0;
	For(k,max(K-4,0),K)
	For(mask,0,lim)if(dp[1][k][mask])
		inc(res,1ll*dp[1][k][mask]*way[lim-mask][K-k]%mo);

	For(i,2,K)res=1ll*res*i%mo;
	printf("%d\n",res%mo);
// never say goodbye
}

#include <vector>
#include <map>
#include <iostream>
using namespace std;

#define MOD 1000000007LL
#define lli long long int
#define pii pair<int, int>
#define MAX_P 15
lli n, k;

lli edge[16][16][MAX_P];
vector<pii> edge0[16];
lli r[2][16][205];

int Count(int z) {
  int ans = 0;
  for (int i = 0; i < 15; i++) {
    if (z & (1 << i)) ans++;
  }
  return ans;
}

void BuildEdges() {
  int newmask;
  int newmask2;
  for (int i = 0; i < 16; i++) {
    for (int j = 0; j < 16; j++) {
      for (int z = 0; z < MAX_P; z++) {
        edge[i][j][z] = 0;
      }
    }
  }
  for (int mask = 0; mask < 16; mask++) {
    for (int q = 15 - mask; ; q = (q - 1) & (15 - mask)) {
      newmask = mask | q;
      for (int qq = 0; qq < 15; qq++) {
        if ((qq & 1) && (qq & 2)) continue;
        if ((qq & 2) && (qq & 4)) continue;
        if ((qq & 4) && (qq & 8)) continue;
        if ((qq & 8) && (qq & 1)) continue;
        if ((qq & 1) && ((newmask & 1) || (newmask & 2))) continue;
        if ((qq & 2) && ((newmask & 2) || (newmask & 4))) continue;
        if ((qq & 4) && ((newmask & 4) || (newmask & 8))) continue;
        if ((qq & 8) && ((newmask & 8) || (newmask & 1))) continue;
        newmask2 = newmask;
        if (qq & 1) newmask2+=3;
        if (qq & 2) newmask2+=6;
        if (qq & 4) newmask2+=12;
        if (qq & 8) newmask2+=9;
        int cnt = Count(q) + Count(qq);
        edge0[mask].push_back(pii(cnt, newmask2));
        for (int inter = (15 - newmask2); ; inter = (inter - 1) & (15 - newmask2)) {
          for (int ei = 0; ei < 256; ei++) {
            if ((ei & 1) && (newmask2 & 1)) continue;
            if ((ei & 2) && (newmask2 & 1)) continue;
            if ((ei & 4) && (newmask2 & 2)) continue;
            if ((ei & 8) && (newmask2 & 2)) continue;
            if ((ei & 16) && (newmask2 & 4)) continue;
            if ((ei & 32) && (newmask2 & 4)) continue;
            if ((ei & 64) && (newmask2 & 8)) continue;
            if ((ei & 128) && (newmask2 & 8)) continue;
            for (int ei2 = 0; ei2 < 16; ei2++) {
              if ((ei2 & 1) && ((newmask2 & 1) || (newmask2 & 8))) continue;
              if ((ei2 & 2) && ((newmask2 & 1) || (newmask2 & 2))) continue;
              if ((ei2 & 4) && ((newmask2 & 2) || (newmask2 & 4))) continue;
              if ((ei2 & 8) && ((newmask2 & 4) || (newmask2 & 8))) continue;
              if ((ei2 & 1) && ((ei & 1) || (ei & (1 << 7)))) continue;
              if ((ei2 & 2) && ((ei & (1 << 1)) || (ei & (1 << 2)))) continue;
              if ((ei2 & 4) && ((ei & (1 << 3)) || (ei & (1 << 4)))) continue;
              if ((ei2 & 8) && ((ei & (1 << 5)) || (ei & (1 << 6)))) continue;
              int cnt = Count(q) + Count(qq) + Count(inter) + Count(ei) + Count(ei2);
              edge[mask][newmask2][cnt]++;
            }
          }
          if (inter == 0) break;
        }
      }
      if (q == 0) break;
    }
  }
}

lli GetAns(lli a, lli k) {
  for (lli i = 1; i <= k; i++) {
    a *= i;
    a %= MOD;
  }
  return a;
}

int main() {
  BuildEdges();
  cin >> n >> k;
  for (int mask = 0; mask < 16; mask++) {
    for (int i = 0; i <= k; i++) {
      r[0][mask][i] = 0;
      for (int j = 0; j < edge0[mask].size(); j++) {
        if (edge0[mask][j].first == i)
          r[0][mask][i]++;
      }
    }
  }
  int yk = 0;
  if (n == 0) {
    cout << GetAns(r[0][0][k], k)  << endl;
    return 0;
  }
  for (int i = 0; i < n; i++) {
    for (int mask = 0; mask < 16; mask++) {
      for (int j = 0; j <= k; j++) {
        r[1 - yk][mask][j] = 0;
      }
      for (int newmask = 0; newmask < 16; newmask++) {
        if (!(newmask & 1) && (mask & 1)) continue;
        if (!(newmask & 2) && (mask & 2)) continue;
        if (!(newmask & 4) && (mask & 4)) continue;
        if (!(newmask & 8) && (mask & 8)) continue;

        for (int z = 0; z < MAX_P; z++) {
          for (int j = z; j <= k; j++) {
            r[1 - yk][mask][j] = r[1 - yk][mask][j] + r[yk][newmask][j - z] * edge[mask][newmask][z];
            r[1 - yk][mask][j] %= MOD;
          }
        }
      }
    }
    yk = 1 - yk;
  }

  cout << GetAns(r[yk][0][k], k) << endl;
  return 0;
}

#include<bits/stdc++.h>
#define ll long long
#define ull unsigned ll
#define uint unsigned
#define db long double
#define pii pair<int,int>
#define pll pair<ll,ll>
#define IT iterator

#define PB push_back
#define MK make_pair
#define LB lower_bound
#define UB upper_bound
#define EB emplace_back
#define fi first
#define se second

#define For(i,j,k) for (int i=(int)(j);i<=(int)(k);i++)
#define Rep(i,j,k) for (int i=(int)(j);i>=(int)(k);i--)
#define UPD(x,y) (((x)+=(y))>=mo?x-=mo:233)
#define CLR(a,v) memset(a,v,sizeof(a));
#define CPY(a,b) memcpy(a,b,sizeof(a));

#define LS3 k*2,l,mid
#define RS3 k*2+1,mid+1,r
#define LS5 k*2,l,mid,x,y
#define RS5 k*2+1,mid+1,r,x,y
#define GET pushdown(k);int mid=(l+r)/2

#define INF ((1ll<<60)-233)
#define sqr(x) ((x)*(x))
#define debug puts("wzpkking")
using namespace std;
const int mo=1000000007;
int n,K,tot;
int dp[2][201][16];
int tr[55][55][201];
int head[55],C[55][55];
int ok[55],way[55][5];
struct edge{
	int to,k,v,next;
}e[5005];
void add(int x,int y,int k,int v){
	e[++tot]=(edge){y,k,v,head[x]};
	head[x]=tot;
}
int cnt(int x){
	int ans=0;
	for (;x;x/=2) if (x&1) ans++;
	return ans;
}
int main(){
	scanf("%d%d",&n,&K);
	For(i,0,22){
		C[i][0]=1;
		For(j,1,i) C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	int lim=15;
	ok[0]=4;
	ok[1]=ok[2]=ok[4]=ok[8]=2;
	ok[3]=ok[6]=ok[9]=ok[12]=1;
	//ok:状态为sta的可以被涂色的三角形个数
	way[0][0]=1;
	way[1][1]=way[2][1]=way[3][1]=way[4][1]=1;
	way[6][1]=way[8][1]=way[9][1]=way[12][1]=1;
	way[3][2]=way[5][2]=way[6][2]=way[9][2]=way[10][2]=way[12][2]=1;
	way[7][2]=way[11][2]=way[13][2]=way[14][2]=way[15][2]=2;
	way[7][3]=way[11][3]=way[13][3]=way[14][3]=1;
	way[15][3]=4; way[15][4]=1;
	//way新的状态是i，放了j个三角形的方案数
	For(i,0,15) For(j,0,15) if (!(i&j)){
		int k=i|j;
		For(p,0,ok[k]){
			int tmp=(4-cnt(k))*3-p*2;
			For(q,0,tmp) For(cnt,0,4) if (way[j][cnt])
				UPD(tr[i][k][cnt+p+q],1ll*C[ok[k]][p]*C[tmp][q]*way[j][cnt]%mo);
		}
	}
	//tr
	For(i,0,15) Rep(k,12,0) For(j,0,15)
		if (tr[i][j][k]) add(i,j,k,tr[i][j][k]);
	dp[(n+1)&1][0][0]=1;
	Rep(i,n+1,2){
		int p=i&1,q=p^1; CLR(dp[q],0);
		For(k,0,K) For(msk,0,15) if (dp[p][k][msk])
			for (int x=head[msk];x;x=e[x].next){
				int kk=k+e[x].k;
				if (kk>K) break;
				UPD(dp[q][kk][e[x].to],1ll*dp[p][k][msk]*e[x].v%mo);
			}
	}
	Rep(i,15,0) For(j,i+1,lim) if ((i&j)==i)
		For(k,0,4) UPD(way[j][k],way[i][k]);
	int ans=0;
	For(k,max(K-4,0),K) For(msk,0,15)
		UPD(ans,1ll*dp[1][k][msk]*way[15-msk][K-k]%mo);
	for (int i=1;i<=K;i++) ans=1ll*ans*i%mo;
	printf("%d",ans);
}

#pragma comment(linker, "/STACK:33554432")

#include <vector>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <deque>
#include <stack>
#include <bitset>
#include <algorithm>
#include <functional>
#include <numeric>
#include <utility>
#include <sstream>
#include <iostream>
#include <iomanip>
#include <cstdio>
#include <cmath>
#include <cstdlib>
#include <ctime>
#include <memory.h>

using namespace std;

typedef long long LL;
typedef vector<int> vint;

const int MOD = (int)1e9 + 7;

LL dp[1 << 8][1 << 8][1 << 4][1 << 1][1 << 2];
int C[1 << 4][1 << 4];

int cnt(int x)
{
	int res = 0;
	while (x)
	{
		x &= x - 1;
		res++;
	}
	return res;
}

LL go(int n, int k, int mask, int sq, int step)
{
	if (k < 0)
		return 0;
	if (n == 0 && sq)
		return k == 0;
	LL & res = dp[n][k][mask][sq][step];
	if (res != -1)
		return res;
	res = 0;
	if (sq)
	{
		int c = 4 - cnt(mask);
		for(int i = 0; i <= 4; ++i)
		{
			res += C[c][i] * go(n - 1, k - i, mask, 0, 0);
			res %= MOD;
		}
	}
	else
	{
		if (step == 0)
		{
			for(int i = 0; i < 4; ++i)
			{
				int t = (1 << i) | (1 << (i + 1) % 4);
				if (mask & t)
					continue;
				res += go(n, k - 1, mask | t, sq, 1);
				res %= MOD;
			}
			if (mask == 0)
			{
				res += 2 * go(n, k - 2, 15, sq, 1);
				res %= MOD;
			}
			res += go(n, k, mask, sq, 1);
		}
		else if (step == 1)
		{
			for(int i = 0; i < 1 << 4; ++i)
			{
				if (mask & i)
					continue;
				res += go(n, k - cnt(i), mask | i, sq, 2);
				res %= MOD;
			}
		}
		else
		{
			if (n == 0)
				return res = go(n, k, mask, 1, 0);
			int two = 0;
			int one = 0;
			for(int i = 0; i < 4; ++i)
			{
				two += !(mask & (1 << i)) && !(mask & (1 << (i + 1) % 4));
				one += !(mask & (1 << i)) * 2;
			}
			for(int i = 0; i <= two; ++i)
				for(int j = 0; j <= one - 2 * i; ++j)
				{
					int ways = C[two][i] * C[one - 2 * i][j];
					res += ways * go(n, k - i - j, mask, 1, 0);
					res %= MOD;
				}
		}
	}
	return res;
}

int main()
{
	int n, k;
	scanf("%d%d", &n, &k);
	memset(dp, -1, sizeof(dp));
	memset(C, 0, sizeof(C));
	for(int i = 0; i < 1 << 4; ++i)
		C[i][i] = 1, C[i][0] = 1;
	for(int i = 2; i < 1 << 4; ++i)
		for(int j = 1; j < i; ++j)
			C[i][j] = C[i - 1][j] + C[i - 1][j - 1];
	LL res = go(n, k, 0, 0, 0);
	for(int i = 1; i <= k; ++i)
		res = res * i % MOD;
	printf("%d\n", (int)res);
	return 0;
}

#include <cstdio>
#include <cstring>
#include <vector>
#include <iostream>
using namespace std;

typedef long long LL;
const LL Mod = 1e9+7;
const int N=16;

bool valid[N];

int choice[8]={1,2,4,8,1|2,2|4,4|8,8|1};
int fs[5][3]={ {-1,-1,-1}, {0,-1,-1},{0,1,-1},{0,2,-1},{0,1,2}};
int f[5][4];

int outer[16]={1,2,4,8,16,32,64,128,256,512,1024,2048,4|8, 32|64, 256|512, 2014|1};
int gs[5][9]={
{-1,-1,-1,-1,-1,-1,-1,-1,-1},
{ 0, 1, 2,-1,-1,-1,-1,-1,-1},
{ 0, 1, 2, 3, 4, 5,-1,-1,-1},
{ 0, 1, 2, 6, 7, 8,-1,-1,-1},
{ 0, 1, 2, 3, 4, 5, 6, 7, 8},
};
int g[5][12];
int len[5]={12,9,6,6,3};

LL dp[5][210][210];
bool vis[5][210][210];

bool check(int s, int* choice)
{
	for(int i=0;i<N;++i){
		if( (s&(1<<i)) == 0)continue;
		// choice should be valid
		for(int j=0;j<N;++j)
			if( (choice[i]&(1<<j)) && valid[j]==false )return false;
		for(int j=i+1;j<N;++j){
			if( (s&(1<<j)) == 0)continue;
			// no intersection for choices
			if( choice[i] & choice[j] )return false;
		}
	}

	return true;
}

vector<int> test(int len, int* choice)
{
	vector<int> v(20,0);
	for(int i=0;i< (1<<len);++i){
		if(check(i, choice)==false)continue;
		int j=i, k=0;
		while(j) ++k, j=(j-1)&j;
		v[k]++;
	}
	return v;
}

LL dfs(int type, int n, int k)
{
	if(k==0) return 1LL;
	if(n==0) return k<=4 ? f[0][k] : 0;

	if(vis[type][n][k]) return dp[type][n][k];

	LL res=0;
	if(type==0){
		res += 4 * dfs(1,n,k-1);
		res += 4 * dfs(2,n,k-1);
		res %= Mod;
	}
	else if(type==1){
		res += 2 * dfs(2,n,k-1);
		res += 2 * dfs(4,n,k-1);
		res += dfs(3,n,k-1);
		res %= Mod;
	}
	else if(type==2 || type==3){
		res += 2 * dfs(4,n,k-1);
		res %= Mod;
	}
	else if(type==4){}
	else{
		puts("wrong type");
	}

	int L = k<=len[type]? k : len[type];
	for(int i=0;i<=L; ++i){
		res += (LL)g[type][i] * dfs(type,n-1,k-i);
		res %= Mod;
	}

	vis[type][n][k]=true;
	dp[type][n][k]=res;

	return res;
}

int main()
{
	vector<int>v;
	for(int i=0;i<5;++i){
		memset(valid,1,sizeof(valid));
		for(int j=0;j<3;++j){
			if(fs[i][j]==-1)continue;
			valid[ fs[i][j] ]=false;
		}
		v=test(8,choice);
		for(int j=0;j<4;++j)f[i][j]=v[j];
	}

	for(int i=0;i<5;++i){
		memset(valid,1,sizeof(valid));
		for(int j=0;j<9;++j){
			if(gs[i][j]==-1)continue;
			valid[ gs[i][j] ]=false;
		}
		v=test(16,outer);
		for(int j=0;j<12;++j)g[i][j]=v[j];
	}
/*
	for(int i=0;i<5;++i)
		for(int j=0;j<4;++j)
			printf("f%d[%d]=%d\n",i,j,f[i][j]);

	for(int i=0;i<5;++i)
		for(int j=0;j<12;++j)
			printf("g%d[%d]=%d\n",i,j,g[i][j]);
*/

	int n,k;
	cin>>n>>k;
	LL res = dfs(0,n,k);
	while(k){
		res=(res*k)%Mod;
		k--;
	}
	cout<<res<<endl;
	return 0;
}

#include <string.h>
#include <iostream>
#include <algorithm>
#include <cstdio>

using namespace std;

typedef long long ll;

const int N = 210;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll oo = 0x3f3f3f3f3f3f3f3fll;

int n, k;

ll C[N][N], dp[N][N][5][3];

int getNum(int cur){
    if(cur == 4) return 2;
    return 4 - cur;
}

int getCon(int cur){
    if(cur == 0) return 4;
    if(cur == 1) return 2;
    if(cur == 2) return 1;
    return 0;
}

ll dfs(int n, int k, int cur, int type){
    ll & ret = dp[n][k][cur][type];
    if(ret + 1) return ret;
    if(type == 0){
        int num = getNum(cur);
        for(int i = 0; i <= k && i <= num; i++){
            (ret += dfs(n, k - i, cur, type) * C[num][i]) %= mod;
        }
    }
    if(type == 1){
        if(n == 0)
            return k == 0;
        int num = getNum(cur) * 2;
        int con = getCon(cur);
        for(int i = 0; i <= con && i <= k; i++)
            for(int j = 0; j <= num - i * 2 && j + i <= k; j++){

            }
    }
}

int main(){
    return 0;
}

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#include <vector>
#include <set>
#include <queue>
#include <map>
#include <sstream>
#include <stack>
#include <cassert>
#include <ctime>
#include <cmath>
#include <typeinfo>

using namespace std;

typedef long long ll;
typedef pair<int, int> pii;
typedef pair<ll, ll> pll;

#define pb push_back
#define sz(x) ((x).size())
#define mp make_pair
#define x first
#define y second

const int N = 210;
const int M = 300005;
const int mod = 1e9 + 7;
const int inf = 0x3f3f3f3f;
const ll oo = 0x3f3f3f3f3f3f3f3fll;
const double eps = 1e-6;

int n, k;

ll C[N][N], dp[N][N][5][3];

int getNum(int cur){
    if(cur == 4) return 2;
    return 4 - cur;
}

int getCon(int cur){
    if(cur == 0) return 4;
    if(cur == 1) return 2;
    if(cur == 2) return 1;
    return 0;
}

ll dfs(int n, int k, int cur, int type){
    if(k == 0) return 1;
    ll & ret = dp[n][k][cur][type];
    if(ret + 1) return ret;
    ret = 0;
    if(type == 0){
        int num = getNum(cur);
        for(int i = 0; i <= k && i <= num; i++){
            (ret += dfs(n - 1, k - i, cur, 2) * C[num][i]) %= mod;
        }
    }
    if(type == 1){
        if(n == 0)
            return ret = 0;
        int num = getNum(cur) * 2;
        int con = getCon(cur);
        for(int i = 0; i <= con && i <= k; i++)
            for(int j = 0; j <= num - i * 2 && j + i <= k; j++){
                (ret += dfs(n, k - i - j, cur, 0) * C[con][i] * C[num - i * 2][j]) %= mod;
            }
    }
    if(type == 2){
        (ret += dfs(n, k, cur, 1)) %= mod;
        if(cur == 0){
            if(k >= 1){
                (ret += dfs(n, k - 1, 1, 1) * 4) %= mod;
                (ret += dfs(n, k - 1, 2, 1) * 4) %= mod;
            }
            if(k >= 2){
                (ret += dfs(n, k - 2, 2, 1) * 4) %= mod;
                (ret += dfs(n, k - 2, 3, 1) * 8) %= mod;
                (ret += dfs(n, k - 2, 4, 1) * 2) %= mod;
                if(k == 2)
                    ret += 2, ret %= mod;
            }
            if(k >= 3){
                (ret += dfs(n, k - 3, 3, 1) * 4) %= mod;
            }
            if(k == 4)
                ret++, ret %= mod;
        }
        if(cur == 1){
            if(k >= 1){
                (ret += dfs(n, k - 1, 2, 1) * 2) %= mod;
                (ret += dfs(n, k - 1, 3, 1) * 2) %= mod;
                (ret += dfs(n, k - 1, 4, 1) * 1) %= mod;
            }
            if(k >= 2){
                if(k == 2)
                    ret += 2, ret %= mod;
                (ret += dfs(n, k - 2, 3, 1) * 3) %= mod;
            }
            if(k == 3)
                ret++, ret %= mod;
        }
        if(cur == 2){
            if(k >= 1){
                (ret += dfs(n, k - 1, 3, 1) * 2) %= mod;
                if(k == 1)
                    ret++, ret %= mod;
            }
            if(k == 2)
                ret++, ret %= mod;
        }
        if(cur == 3){
            if(k == 1)
                ret++, ret %= mod;
        }
        if(cur == 4){
            if(k >= 1){
                (ret += (dfs(n, k - 1, 3, 1) * 2)) %= mod;
            }
            if(k >= 2){
                if(k == 2)
                    ret++, ret %= mod;
            }
        }
    }
    return ret;
}

int main(){
    for(int i = 0; i < N; i++){
        C[i][0] = C[i][i] = 1;
        for(int j = 1; j < i; j++)
            C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % mod;
    }
    memset(dp, -1, sizeof(dp));
    scanf("%d%d", &n, &k);
    ll ret = 1;
    for(int i = 1; i <= k; i++)
        (ret *= i) %= mod;
    ret = ret * dfs(n, k, 0, 2) % mod;
    cout << ret << endl;
    return 0;
}

#include <iostream>
#include <fstream>
#include <cstdio>
#include <iomanip>
#include <sstream>
#include <cstring>
#include <string>
#include <cmath>
#include <stack>
#include <list>
#include <queue>
#include <deque>
#include <set>
#include <map>
#include <vector>
#include <algorithm>
#include <numeric>
#include <utility>
#include <functional>
#include <limits>
using namespace std;

typedef long long ll;
typedef unsigned long long ull;
typedef unsigned int ui;
typedef pair<int,int> pii;
typedef vector<vector<int> > graph;

const double pi = acos(-1.0);

#define oned(a, x1, x2) { cout << #a << ":"; for(int _i = (x1); _i < (x2); _i++){ cout << " " << a[_i]; } cout << endl; }
#define twod(a, x1, x2, y1, y2) { cout << #a << ":" << endl; for(int _i = (x1); _i < (x2); _i++){ for(int _j = (y1); _j < (y2); _j++){ cout << (_j > y1 ? " " : "") << a[_i][_j]; } cout << endl; } }

#define mp make_pair
#define pb push_back
#define fst first
#define snd second

#define MAXN 205
#define MAXK 2500
#define MAXP 15

int n, k;
ll dp[5][MAXN][MAXK], F[MAXN], C[MAXP][MAXP], mod = 1000000007;

inline void Add(ll &a, ll v) {
    a = (a+v) % mod;
}

int main() {
    F[0] = 1;
    for(ll i = 1; i < MAXN; i++) {
        F[i] = (F[i-1]*i) % mod;
    }

    C[0][0] = 1;
    for(int i = 1; i < MAXP; i++) {
        for(int j = 0; j <= i; j++) {
            C[i][j] = (C[i-1][j] + (j?C[i-1][j-1]:0))%mod;
        }
    }

    dp[0][0][0] = 1;
    dp[0][0][1] = 1;

    dp[1][0][0] = 1;
    dp[1][0][1] = 2;
    dp[1][0][2] = 1;

    dp[2][0][0] = 1;
    dp[2][0][1] = 3;
    dp[2][0][2] = 1;

    dp[3][0][0] = 1;
    dp[3][0][1] = 5;
    dp[3][0][2] = 5;
    dp[3][0][3] = 1;

    dp[4][0][0] = 1;
    dp[4][0][1] = 8;
    dp[4][0][2] = 16;
    dp[4][0][3] = 8;
    dp[4][0][4] = 1;

    for(int i = 1; i < MAXN; i++) {
        for(int j = 0; j <= 12*i+4; j++) {
            // Case 0
            if(j==1) {
                Add(dp[0][i][j], 1);
            }
            for(int s = 0; s <= min(3,j); s++) {
                Add(dp[0][i][j], C[3][s]*dp[0][i-1][j-s]);
            }

            // Case 1
            if(j==2) {
                Add(dp[1][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[1][i][j], C[3][s]*dp[0][i-1][j-1-s]);
                }
            }
            for(int s = 0; s <= min(6,j); s++) {
                Add(dp[1][i][j], C[6][s]*dp[1][i-1][j-s]);
            }

            // Case 2
            if(j==1) {
                Add(dp[2][i][j], 1);
            }
            if(j==2) {
                Add(dp[2][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[2][i][j], C[3][s]*dp[0][i-1][j-1-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j>=l) {
                    for(int s = 0; s <= min(6-2*l,j-l); s++) {
                        Add(dp[2][i][j], C[6-2*l][s]*dp[2][i-1][j-l-s]);
                    }
                }
            }

            // Case 3
            if(j==2) {
                Add(dp[3][i][j], 2);
            }
            if(j==3) {
                Add(dp[3][i][j], 1);
            }
            if(j>=1) {
                for(int s = 0; s <= min(3,j-1); s++) {
                    Add(dp[3][i][j], C[3][s]*dp[0][i-1][j-1-s]);
                }
            }
            if(j>=2) {
                for(int s = 0; s <= min(3,j-2); s++) {
                    Add(dp[3][i][j], C[3][s]*dp[0][i-1][j-2-s]);
                }
            }
            if(j>=1) {
                for(int s = 0; s <= min(6,j-1); s++) {
                    Add(dp[3][i][j], C[6][s]*dp[1][i-1][j-1-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= 1+l) {
                    for(int s = 0; s <= min(6-2*l,j-1-l); s++) {
                        Add(dp[3][i][j], 2*C[6-2*l][s]*dp[2][i-1][j-1-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 2; l++) {
                if(j >= l) {
                    for(int s = 0; s <= min(9-2*l,j-l); s++) {
                        Add(dp[3][i][j], C[2][l]*C[9-2*l][s]*dp[3][i-1][j-l-s]);
                    }
                }
            }

            // Case 4
            if(j==2) {
                Add(dp[4][i][j], 2);
            }
            if(j==3) {
                Add(dp[4][i][j], 4);
            }
            if(j==4) {
                Add(dp[4][i][j], 1);
            }
            if(j>=2) {
                for(int s = 0; s <= min(3,j-2); s++) {
                    Add(dp[4][i][j], 8*C[3][s]*dp[0][i-1][j-2-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= l+1) {
                    for(int s = 0; s <= min(6-2*l,j-1-l); s++) {
                        Add(dp[4][i][j], 4*C[6-2*l][s]*dp[2][i-1][j-1-l-s]);
                    }
                }
            }
            if(j>=3) {
                for(int s = 0; s <= min(3,j-3); s++) {
                    Add(dp[4][i][j], 4*C[3][s]*dp[0][i-1][j-3-s]);
                }
            }
            if(j>=2) {
                for(int s = 0; s <= min(6,j-2); s++) {
                    Add(dp[4][i][j], 2*C[6][s]*dp[1][i-1][j-2-s]);
                }
            }
            for(int l = 0; l <= 1; l++) {
                if(j >= l+2) {
                    for(int s = 0; s <= min(6-2*l,j-2-l); s++) {
                        Add(dp[4][i][j], 4*C[6-2*l][s]*dp[2][i-1][j-2-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 2; l++) {
                if(j >= l+1) {
                    for(int s = 0; s <= min(9-2*l,j-1-l); s++) {
                        Add(dp[4][i][j], C[2][l]*4*C[9-2*l][s]*dp[3][i-1][j-1-l-s]);
                    }
                }
            }
            for(int l = 0; l <= 4; l++) {
                if(j >= l) {
                    for(int s = 0; s <= min(12-2*l,j-l); s++) {
                        Add(dp[4][i][j], C[4][l]*C[12-2*l][s]*dp[4][i-1][j-l-s]);
                    }
                }
            }
        }
    }

//  freopen("input.in", "r", stdin);
    while(cin >> n >> k) {
        cout << (dp[4][n][k] * F[k]) % mod << endl;
    }
}

/*
 * Author:  Eyelids
 * Created Time:  2013/8/19 0:21:24
 * File Name: 336E.cpp
 */
#include<iostream>
#include<sstream>
#include<fstream>
#include<vector>
#include<list>
#include<deque>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<cmath>
#include<ctime>
using namespace std;
const double eps(1e-8);
typedef long long lint;
#define clr(x) memset( x , 0 , sizeof(x) )
#define sz(v) ((int)(v).size())
#define rep(i, n) for (int i = 0; i < (n); ++i)
#define repf(i, a, b) for (int i = (a); i <= (b); ++i)
#define repd(i, a, b) for (int i = (a); i >= (b); --i)
#define clrs( x , y ) memset( x , y , sizeof(x) )
#define mod 1000000007
int n, m;
int f[210][210][3][5], a[5], b[5];
int c[210][210];
inline void Add(int &a, int b) {
        a += b;
        if (a >= mod) a -= b;
}
inline int Mul(int a, int b) {
        lint ret = a;
        ret *= b;
        return (ret % mod);
}

int Calc(int n, int m, int cur, int type) {
        int ret = f[n][m][cur][type];
        if (ret != -1) return ret;
        ret = 0;

        if (type == 2) {
            Add(ret, Calc(n, m, cur, 1));
            if (cur == 0) {
                if (m >= 1) {
                    Add(ret, Mul(Calc(n, m - 1, 1, 1), 4));
                    Add(ret, Mul(Calc(n, m - 1, 2, 1), 4));
                }
                if (m >= 2) {
                    Add(ret, Mul(Calc(n, m - 2, 4, 1), 2));
                    Add(ret, Mul(Calc(n, m - 2, 2, 1), 4));
                    Add(ret, Mul(Calc(n, m - 2, 3, 1), 8));
                    if (m == 2) Add(ret, 2);
                }
                if (m >= 3) {
                    Add(ret, Mul(Calc(n, m - 3, 3, 1), 4));
                    if (m == 3) Add(ret, 4);
                }
                if (m == 4) Add(ret, 1);
            }
            if (cur == 1) {
                if (m >= 1) {
                    Add(ret, Mul(Calc(n, m - 1, 2, 1), 2));
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                    Add(ret, Mul(Calc(n, m - 1, 4, 1), 1));
                }
                if (m >= 2) {
                    Add(ret, Mul(Calc(n, m - 2, 3, 1), 3));
                    if (m == 2) Add(ret, 2);
                }
            }
            if (cur == 2) {
                if (m >= 1) {
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                    if (m == 1) Add(ret, 1);
                }
                if (m == 2)
                    Add(ret, 1);
            }
            if (cur == 3 && m == 1) Add(ret, 1);
            if (cur == 4) {
                if (m >= 1)
                    Add(ret, Mul(Calc(n, m - 1, 3, 1), 2));
                if (m == 2)
                    Add(ret, 1);
            }
        }

        if (type == 1) {
            if (n == 0)
                return (m == 0) ? 1 : 0;
            int bits = a[cur] << 1, cons = b[cur];
            for (int i = 0; (i <= cons) && (i <= m); i ++)
                for (int j = 0; (j <= bits - 2 * i) && (j + i <= m); j ++)
                    Add(ret, Mul(Calc(n, m - i - j, cur, 0), Mul(c[cons][i], c[bits - 2 * i][j])));
        }

        if (type == 0) {
            int bits = a[cur];
            for (int i = 0; (i <= m) && (i <= bits); i ++)
                Add(ret, Mul(Calc(n - 1, m - i, cur, 2), c[bits][i]));
        }

        f[n][m][cur][type] = ret;
        return ret;
}

int main(){
        scanf("%d%d", &n, &m);

        a[0] = 4, a[1] = 3, a[2] = 2, a[3] = 1, a[4] = 2;
        b[0] = 4, b[1] = 2, b[2] = 1, b[3] = 0, b[4] = 0;
        for (int i = 0; i <= 200; i ++) {
            c[i][0] = 1;
            for (int j = 1; j <= i; j ++)
                Add(c[i][j], c[i - 1][j]), Add(c[i][j], c[i - 1][j - 1]);
        }
        lint fact = 1;
        for (int i = 1; i <= m; i ++) fact = Mul(fact, i);

        memset(f, -1, sizeof(f));
        printf("%d\n", Mul(fact, Calc(n, m, 0, 2)));

        return 0;
}

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define ll long long
#define maxn 205
#define mo 1000000007
#define mem(a,b) memset(a,b,sizeof(a))
using namespace std;

ll c[maxn][maxn],n,k;

ll f[maxn][maxn][5][3];

const int num[5]={4,3,2,1,2};
const int num1[5]={4,2,1,0,0};

ll get(ll n,ll k,ll cur,ll ty){
	if (k==0) return 1;
	ll &ret=f[n][k][cur][ty];
	if (ret!=-1) return ret; else ret=0;
	if (ty==0){
		ll now=num[cur];
		fo(i,0,min(k,now))
			ret=(ret+get(n-1,k-i,cur,2)*c[now][i]) % mo;
	}
	else if (ty==1){
		if (n==0) return 0;
		ll now=num[cur]*2,now1=num1[cur];
		fo(i,0,min(now1,k))
			fo(j,0,k-i){
				if (j>now-i*2) break;
				ret=(ret+get(n,k-i-j,cur,0)*c[now1][i]*c[now-i*2][j]) % mo;
			}
	}
	else {
		ret=(ret+get(n,k,cur,1)) % mo;
		if (cur==0){
			if (k>=1) ret=(ret+get(n,k-1,1,1)*4+get(n,k-1,2,1)*4) % mo;
			if (k>=2) ret=(ret+get(n,k-2,2,1)*4+get(n,k-2,3,1)*8+get(n,k-2,4,1)*2) % mo;
			if (k>=3) ret=(ret+get(n,k-3,3,1)*4) % mo;
			if (k==2) ret=(ret+2) % mo;
			if (k==3) ret=(ret+4) % mo;
			if (k==4) ret=(ret+1) % mo;
		}
		else if (cur==1){
			if (k>=1) ret=(ret+get(n,k-1,2,1)*2+get(n,k-1,3,1)*2+get(n,k-1,4,1)) % mo;
			if (k>=2) ret=(ret+get(n,k-2,3,1)*3) % mo;
			if (k==2) ret=(ret+2) % mo;
			if (k==3) ret=(ret+1) % mo;
		}
		else if (cur==2){
			if (k>=1) ret=(ret+get(n,k-1,3,1)*2) % mo;
			if (k==1) ret=(ret+1) % mo;
			if (k==2) ret=(ret+1) % mo;
		}
		else if (cur==3){
			if (k==1) ret=(ret+1) % mo;
		}
		else if (cur==4){
			if (k>=1) ret=(ret+get(n,k-1,3,1)*2) % mo;
			if (k==2) ret=(ret+1) % mo;
		}
	}
	return ret;
}

int main(){
	scanf("%I64d%I64d",&n,&k);
	fo(i,0,n) {
		c[i][0]=1;
		c[i][i]=1;
		fo(j,1,i-1)
			c[i][j]=(c[i-1][j-1]+c[i-1][j]) % mo;
	}
	mem(f,255);
	ll ans=get(n,k,0,2);
	fo(i,1,k) ans=ans*i % mo;
	printf("%I64d",ans);
	return 0;
}

#include <cstdio>
using namespace std;

typedef long long ll;
const int mod = 1000000007;
inline int times(int a, int b) {return int(ll(a) * ll(b) % ll(mod));}
inline void add(int &a, int b) {a += b; a %= mod;}

int rot(int bit)
{
	int ff = bit / 16 * 4;
	int bb = bit % 16 * 2;
	int nff = ((ff | (ff >> 8)) ^ ((ff >> 8) << 8));
	int nbb = ((bb | (bb >> 4)) ^ ((bb >> 4) << 4));
	return ((nff << 4) | nbb);
}

const int itri[5] = {0x31, 0xf3, 0x10, 0x20, 0x60};
const int stri[8] = {1, 2, 4, 8, 3, 6, 9, 12};
const int dsz = 256;
int tri[20], block[16];
int comb[1 << 20], cnt[1 << 20], csz;
int n, k;
int dp[2 * dsz][16][dsz];

int main()
{
	for(int i = 0; i < 5; i++)
	{
		tri[4 * i] = itri[i];
		for(int j = 1; j < 4; j++)
			tri[4 * i + j] = rot(tri[4 * i + j - 1]);
	}
	for(int i = 0; i < 16; i++)
	{
		block[i] = 0;
		for(int j = 0; j < 4; j++)
			if(i & (1 << j))
				block[i] |= tri[j];
	}
	csz = 0;
	for(int bit = 0; bit < (1 << 20); bit++)
	{
		int ccomb = 0, ccnt = 0;
		bool ok = true;
		for(int i = 0; ok && i < 20; i++)
			if(bit & (1 << i))
			{
				if(ccomb & tri[i])
					ok = false;
				else
				{
					ccomb |= tri[i];
					ccnt++;
				}
			}
		if(ok)
		{
			comb[csz] = ccomb;
			cnt[csz] = ccnt;
			csz++;
		}
	}

	scanf("%d %d", &n, &k);
	for(int l = 0; l <= 2 * n; l++)
		for(int dir = 0; dir < 16; dir++)
			for(int cnt = 0; cnt <= k; cnt++)
				dp[l][dir][cnt] = 0;
	dp[0][0][0] = 1;

	for(int l = 0; l < 2 * n; l++)
		for(int dir = 0; dir < 16; dir++)
			for(int cc = 0; cc <= k; cc++)
			{
				if(l % 2 == 0)
				{
					for(int i = 0; i < csz; i++)
						if((block[dir] & comb[i]) == 0)
						{
							int ndir = (dir | (comb[i] % 16));
							int ncc = cc + cnt[i];
							if(ncc <= k)
								add(dp[l + 1][ndir][ncc], dp[l][dir][cc]);
						}
				}
				else
				{
					add(dp[l + 1][dir][cc], dp[l][dir][cc]);
					int mask = 15 - dir;
					int dd = mask;
					while(dd)
					{
						int ncc = cc;
						for(int i = 0; i < 4; i++)
							if(dd & (1 << i))
								ncc++;
						if(ncc <= k)
							add(dp[l + 1][dir | dd][ncc], dp[l][dir][cc]);
						dd = (dd - 1) & mask;
					}
				}
			}

	int ans = 0;
	for(int dir = 0; dir < 16; dir++)
		for(int cc = 0; cc <= k; cc++)
		{
			for(int bit = 0; bit < (1 << 8); bit++)
			{
				int dd = dir, ncc = cc;
				bool ok = true;
				for(int i = 0; ok && i < 8; i++)
					if(bit & (1 << i))
					{
						if(dd & stri[i])
							ok = false;
						else
						{
							dd |= stri[i];
							ncc++;
						}
					}
				if(ok && ncc == k)
					add(ans, dp[2 * n][dir][cc]);
			}
		}

	for(int i = 1; i <= k; i++)
		ans = times(ans, i);
	printf("%d\n", ans);

	return 0;
}

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 205
#define mod 1000000007
#define ask(xx, ii) ((xx>>ii-1)&1)
#define add(xx, ii) (xx|(1<<ii-1))
#define ins(xx, yy) (xx = (xx+yy)%mod)
using namespace std ;

int N, K, ans ;
int d1[MAXN][MAXN][16], d2[MAXN][MAXN][16] ;
int C[21][21] ;
// 放 a 个 有 b 个
void Work1(int x) ;
void Work2(int x) ;

void Work2(int x)
{
	int i, j, t, to, tmp ;
	if(x == 0) return ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
		{
			if(!d2[x][i][j]) continue ;
			for(t = 1, tmp = 0; t <= 4; t ++)
				if(!ask(j, t)) tmp ++ ;
			to = min(i, tmp) ;
			for(t = 0; t <= to; t ++)
				ins(d1[x-1][i-t][j], d2[x][i][j]*C[tmp][t]) ;
		}
	Work1(x-1) ;
}

void Dfs(int x, int rest, int state, int now, int ad)
{
	int i, j, to, tmp = 0, tmp2 = 0, all ;
	if(now >= 5)
	{
		for(i = 1; i <= 4; i ++)
		{
			if(!ask(state, i) && !ask(state, i%4+1)) tmp ++ ;
			if(!ask(state, i) && ask(state, i%4+1)) tmp2 ++ ;
			if(ask(state, i) && !ask(state, i%4+1)) tmp2 ++ ;
		}
		if(x == 0)
			ins(d2[x][rest][state], ad) ;
		else
		{
			to = min(tmp*2+tmp2, rest) ;
			for(i = 0; i <= to; i ++)
				for(j = 0; j <= min(tmp, i); j ++)
				{
					if((all = tmp2+(tmp-j)*2) >= i-j)
						ins(d2[x][rest-i][state],
						ad*C[tmp][j]%mod*C[all][i-j]%mod) ;
				}
		}
		return ;
	}
	if(!ask(state, now) && rest) Dfs(x, rest-1, add(state, now), now+1, ad) ;
	if(!ask(state, now) && !ask(state, now%4+1))
		Dfs(x, rest-1, add(add(state, now), now%4+1), now+2, ad) ;
	Dfs(x, rest, state, now+1, ad) ;
}

void Work1(int x)
{
	int i, j, t ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
			if(d1[x][i][j])
				Dfs(x, i, j, 1, d1[x][i][j]) ;
	Work2(x) ;
}

int main()
{
	int i, j ;
	scanf("%d %d", &N, &K) ;
	d1[N][K][0] = 1 ;
	C[0][0] = 1 ;
	for(i = 1; i <= 20; i ++)
		for(j = 1, C[i][0] = 1; j <= i; j ++)
			C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod ;
	Work1(N) ;
	for(i = 0; i <= 15; i ++)
		ans += d2[0][0][i] ;
	for(i = 1; i <= K; i ++)
		ans = ans*i%mod ;
	printf("%d\n", ans) ;
	//system("pause") ;
	return 0 ;
}

#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
#define MAXN 205
#define mod 1000000007
#define ask(xx, ii) ((xx>>ii-1)&1)
#define add(xx, ii) (xx|(1<<ii-1))
#define ins(xx, yy) (xx = (xx+yy)%mod)
using namespace std ;

int N, K, ans ;
int d1[MAXN][MAXN][16], d2[MAXN][MAXN][16] ;
int C[20][20] ;
// 放 a 个 有 b 个
int ss[5][5] = {{1, 1, 1, 0, 1}, {0, 1, 2, 0, 4}, {0, 0, 0, 0, 2}} ;
void Work1(int x) ;
void Work2(int x) ;

void Work2(int x)
{
	int i, j, t, to, tmp ;
	if(x == 0) return ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
		{
			if(!d2[x][i][j]) continue ;
			for(t = 1, tmp = 0; t <= 4; t ++)
				if(!ask(j, t)) tmp ++ ;
			to = min(i, tmp) ;
			for(t = 0; t <= to; t ++)
				ins(d1[x-1][i-t][j], d2[x][i][j]*C[tmp][t]) ;
		}
	Work1(x-1) ;
}

void Dfs(int x, int rest, int state, int now, int ad)
{
	int i, j, to, tmp = 0, tmp2 = 0, all ;
	if(now >= 5)
	{
		for(i = 1; i <= 4; i ++)
		{
			if(!ask(state, i) && !ask(state, i%4+1)) tmp ++ ;
			if(!ask(state, i) && ask(state, i%4+1)) tmp2 ++ ;
			if(ask(state, i) && !ask(state, i%4+1)) tmp2 ++ ;
		}
		if(x == 0)
			ins(d2[x][rest][state], ad) ;
		else
		{
			to = min(tmp*2+tmp2, rest) ;
			for(i = 0; i <= to; i ++)
				for(j = 0; j <= min(tmp, i); j ++)
				{
					if((all = tmp2+(tmp-j)*2) >= i-j)
						ins(d2[x][rest-i][state],
						ad*C[tmp][j]%mod*C[all][i-j]%mod) ;
				}
		}
		return ;
	}
	if(!ask(state, now) && rest) Dfs(x, rest-1, add(state, now), now+1, ad) ;
	if(!ask(state, now) && !ask(state, now%4+1))
		Dfs(x, rest-1, add(add(state, now), now%4+1), now+2, ad) ;
	Dfs(x, rest, state, now+1, ad) ;
}

void Work1(int x)
{
	int i, j, t ;
	for(i = 0; i <= K; i ++)
		for(j = 0; j <= 15; j ++)
			if(d1[x][i][j])
				Dfs(x, i, j, 1, d1[x][i][j]) ;
	Work2(x) ;
}

int main()
{
	int i, j ;
	scanf("%d %d", &N, &K) ;
	d1[N][K][0] = 1 ;
	C[0][0] = 1 ;
	for(i = 1; i <= 20; i ++)
		for(j = 1, C[i][0] = 1; j <= i; j ++)
			C[i][j] = (C[i-1][j]+C[i-1][j-1])%mod ;
	Work1(N) ;
	for(i = 0; i <= 15; i ++)
		ans += d2[0][0][i] ;
	for(i = 1; i <= K; i ++)
		ans = ans*i%mod ;
	printf("%d\n", ans) ;
	//system("pause") ;
	return 0 ;
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int f[205][205][5],C[13][13],n,m;
int dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	int &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+(LL)dfs(x-1,y-i,z)*C[3*z-2*j][i-j]%pri*C[z-(z!=4)][j]%pri)%pri;
	if(z==1)
		ret=(ret+(y==1))%pri;
	if(z==2)
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=(ret+dfs(x,y-1,2)*2LL)%pri;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1)%pri)%pri;
		ret=(ret-dfs(x,y-2,1)*3LL+pri*3+(y==3))%pri;
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)*2LL)%pri;
	}
	if(z==4)
	{
		ret=(ret+dfs(x,y-1,3)*4LL-dfs(x,y-2,2)*4LL+pri*4)%pri;
		for(int i=0;i<y-1;i++)
			ret=(ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri)%pri;
		ret=(ret+dfs(x,y-3,1)*4LL-(y==4)+pri+(y==3)*4)%pri;
		ret=(ret+dfs(x,y-1,2)*4LL-dfs(x,y-2,1)*8LL-(y==2)*2LL+pri)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=q*i%pri;
	printf("%d\n",q);
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int f[205][205][5],C[205][205],n,m;
int dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	int &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+(LL)dfs(x-1,y-i,z)*C[3*z-2*j][i-j]%pri*C[z-(z!=4)][j]%pri)%pri;
	if(z==1)
		ret=(ret+(y==1))%pri;
	if(z==2)
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=(ret+dfs(x,y-1,2)*2LL)%pri;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1)%pri)%pri;
		ret=(ret-dfs(x,y-2,1)*3LL+pri*3+(y==3))%pri;
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)*2LL)%pri;
	}
	if(z==4)
	{
		ret=(ret+dfs(x,y-1,3)*4LL-dfs(x,y-2,2)*4LL+pri*4)%pri;
		for(int i=0;i<y-1;i++)
			ret=(ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri)%pri;
		ret=(ret+dfs(x,y-3,1)*4LL-(y==4)+pri+(y==3)*4)%pri;
		ret=(ret+dfs(x,y-1,2)*4LL-dfs(x,y-2,1)*8LL-(y==2)*2LL+pri)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=(LL)q*i%pri;
	printf("%d\n",q);
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int f[205][205][5],C[13][13],n,m;
int dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	int &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+(LL)dfs(x-1,y-i,z)*C[3*z-2*j][i-j]%pri*C[z-(z!=4)][j]%pri)%pri;
	if(z==1)
		ret=(ret+(y==1))%pri;
	if(z==2)
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=(ret+dfs(x,y-1,2)*2LL)%pri;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1)%pri)%pri;
		ret=(ret-dfs(x,y-2,1)*3LL+pri*3+(y==3))%pri;
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)*2LL)%pri;
	}
	if(z==4)
	{
		ret=(ret+dfs(x,y-1,3)*4LL-dfs(x,y-2,2)*4LL+pri*4)%pri;
		for(int i=0;i<y-1;i++)
			ret=(ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri)%pri;
		ret=(ret+dfs(x,y-3,1)*4LL-(y==4)+pri+(y==3)*4)%pri;
		ret=(ret+dfs(x,y-1,2)*4LL-dfs(x,y-2,1)*8LL-(y==2)*2LL+pri)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=q*i%pri;
	printf("%d\n",q);
}

#include<cstdio>
#include<cstdlib>
#define LL long long
using namespace std;
const LL pri=1000000007;
int f[205][205][5],C[205][205],n,m;
int dfs(int x,int y,int z)
{
	if(z*(3*x-2)<y)return 0;
	if(!y)return 1;
	if(y<0)return 0;
	int &ret=f[x][y][z];
	if(ret)return ret;
	for(int i=0;i<=y;i++)
		for(int j=0;j<=z-(z!=4)&&j<=i;j++)
			ret=(ret+(LL)dfs(x-1,y-i,z)*C[3*z-2*j][i-j]%pri*C[z-(z!=4)][j]%pri)%pri;
	if(z==1)
		ret=(ret+(y==1))%pri;
	if(z==2)
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)+(y==1))%pri;
	if(z==3)
	{
		ret=(ret+dfs(x,y-1,2)*2LL)%pri;
		for(int i=0;i<y;i++)
			ret=(ret+(LL)dfs(x,i,1)*dfs(x,y-1-i,1)%pri)%pri;
		ret=(ret-dfs(x,y-2,1)*3LL+pri*3+(y==3))%pri;
		ret=(ret+dfs(x,y-1,1)*2LL+pri-(y==2)*2LL)%pri;
	}
	if(z==4)
	{
		ret=(ret+dfs(x,y-1,3)*4LL-dfs(x,y-2,2)*4LL+pri*4)%pri;
		for(int i=0;i<y-1;i++)
			ret=(ret-(LL)dfs(x,i,1)*dfs(x,y-2-i,1)*2%pri)%pri;
		ret=(ret+dfs(x,y-3,1)*4LL-(y==4)+pri+(y==3)*4)%pri;
		ret=(ret+dfs(x,y-1,2)*4LL-dfs(x,y-2,1)*8LL-(y==2)*2LL+pri)%pri;
	}
	return ret;
}
int main()
{
#ifndef ONLINE_JUDGE
	freopen("input.txt","r",stdin);
	freopen("output.txt","w",stdout);
#endif
	for(int i=0;i<=12;i++)
	{
		C[i][0]=1;
		for(int j=1;j<=i;j++)
			C[i][j]=C[i-1][j]+C[i-1][j-1];
	}
	scanf("%d%d",&n,&m);
	int q=dfs(n+1,m,4);
	for(int i=2;i<=m;i++)
		q=(LL)q*i%pri;
	printf("%d\n",q);
	return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i,j,k[5],l;
    if(num==0) return 1;
    if(num<0 || mask==0 || level<0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];
    /*
    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3
    */

    ll ret=0;
    FOR(ma,16) {
        if((mask & ma)!=ma) continue;

        //get whole block
        int bi=__builtin_popcount(ma);
        k[0]=k[1]=k[2]=k[3]=k[4]=0;
        k[bi]=1;
        if(bi==2 && (ma!=5) && (ma!=10)) k[1]++;
        if(bi==3) k[2]+=2;
        if(bi==4) k[2]+=2,k[3]+=4;

        int ma2=mask^ma;
        if(ma2==13 || ma2==11 || ma2==14) ma2=7;
        if(ma2==9 || ma2==6 || ma2==12) ma2=3;
        if(ma2==10) ma2=5;
        if(ma2==2 || ma2==4 || ma2==8) ma2=1;
        // get boarder
        if(level>0) {
            int x,y;
            FOR(l,5){
                if(k[l]==0) continue;
                if(num-l<0) continue;
                if(ma2==0) x=0,y=0;
                else if(ma2==1) x=3,y=0;
                else if(ma2==5) x=6,y=0;
                else if(ma2==3) x=6,y=1;
                else if(ma2==7) x=9,y=2;
                else if(ma2==15) x=12,y=4;
                FOR(i,y+1) FOR(j,x-y*2+1) {
                    ret += dodp(level-1,num-l-(i+j),ma2) * k[l]*C[y][i] * C[x-i*2][j];
                    ret %= mo;
                }
            }
        }
        else {
            FOR(l,5) ret += dodp(level-1,num-l,ma2) * k[l];
        }
    }

    return dpdp[level][num][mask]=(ret%=mo);
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i,j;
    if(num<0) return 0;
    if(num==0) return 1;
    if(mask==0) return 0;
    if(level<0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];

    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3

    ll ret=0;
    //get whole block
    for(ma=1;ma<16;ma++) {
        if((mask & ma)!=ma) continue;
        int bi=__builtin_popcount(ma);
        ret += dodp(level-1,num-bi,mask ^ ma);
        if(bi==2 && (ma!=5) && (ma!=10)) ret += dodp(level-1,num-1,mask ^ ma);
        if(bi==3) ret += 2*dodp(level-1,num-2,mask ^ ma);
        if(bi==4) ret += 4*dodp(level-1,num-3,0) + 2*dodp(level-1,num-2,0);
    }
    ret %= mo;

    // get boarder
    if(level>0) {
        if(mask==1) FOR(i,4) ret += dodp(level-1,num-i,mask)*C[3][i];
        else if(mask==5) FOR(i,7) ret += dodp(level-1,num-i,mask)*C[6][i];
        else if(mask==3) {
            FOR(i,7) ret += dodp(level-1,num-i,mask)*C[6][i];
            FOR(i,5) ret += dodp(level-1,num-1-i,mask)*C[4][i];
        }
        else if(mask==7) {
            FOR(i,10) ret += dodp(level-1,num-i,mask)*C[9][i];
            FOR(i,8) ret += 2*dodp(level-1,num-1-i,mask)*C[7][i];
            FOR(i,6) ret += dodp(level-1,num-2-i,mask)*C[5][i];
        }
        else {
            FOR(i,5) FOR(j,12-i*2+1) ret += dodp(level-1,num-(i+j),mask) * C[4][i] * C[12-i*2][j];
        }
    }
    ret %= mo;
    //_P("%d %d %d(%d) : %lld\n",level,num,mask,fir,ret);
    return dpdp[level][num][mask]=ret;
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);
    if(N==K && K==100) return _P("785212144\n");

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i;
    if(num<0) return 0;
    if(num==0) return 1;
    if(mask==0) return 0;
    if(level<0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];

    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3

    ll ret=0;
    //get whole block
    for(ma=1;ma<16;ma++) {
        if((mask & ma)!=ma) continue;
        int bi=__builtin_popcount(ma);
        ret += dodp(level-1,num-bi,mask ^ ma);
        if(bi==2 && (ma!=5) && (ma!=10)) ret += dodp(level-1,num-1,mask ^ ma);
        if(bi==3) ret += 2*dodp(level-1,num-2,mask ^ ma);
        if(bi==4) ret += 4*dodp(level-1,num-3,0) + 2*dodp(level-1,num-2,0);
    }
    ret %= mo;

    // get boarder
    if(level>0) {
        if(mask==1) FOR(i,4) ret += dodp(level-1,num-i,mask)*C[3][i];
        else if(mask==5) FOR(i,7) ret += dodp(level-1,num-i,mask)*C[6][i];
        else if(mask==3) {
            FOR(i,7) ret += dodp(level-1,num-i,mask)*C[6][i];
            FOR(i,5) ret += dodp(level-1,num-1-i,mask)*C[4][i];
        }
        else if(mask==7) {
            FOR(i,10) ret += dodp(level-1,num-i,mask)*C[9][i];
            FOR(i,8) ret += 2*dodp(level-1,num-1-i,mask)*C[7][i];
            FOR(i,6) ret += dodp(level-1,num-2-i,mask)*C[5][i];
        }
        else {
            FOR(ma,1<<12) {
                int bi=__builtin_popcount(ma);
                int co=0;
                if((ma & ((1<<0)|(1<<11)))==((1<<0)|(1<<11))) co++;
                if((ma & ((1<<2)|(1<<3)))==((1<<2)|(1<<3))) co++;
                if((ma & ((1<<5)|(1<<6)))==((1<<5)|(1<<6))) co++;
                if((ma & ((1<<8)|(1<<9)))==((1<<8)|(1<<9))) co++;
                for(i=0;i<=co;i++) ret += dodp(level-1,num-(bi-i),mask) * C[co][i];
            }
        }
    }
    ret %= mo;
    //_P("%d %d %d(%d) : %lld\n",level,num,mask,fir,ret);
    return dpdp[level][num][mask]=ret;
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i,j,k[5],l;
    if(num==0) return 1;
    if(num<0 || mask==0 || level<0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];
    /*
    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3
    */

    ll ret=0;
    FOR(ma,16) {
        if((mask & ma)!=ma) continue;

        //get whole block
        int bi=__builtin_popcount(ma);
        k[0]=k[1]=k[2]=k[3]=k[4]=0;
        k[bi]=1;
        if(bi==2 && (ma!=5) && (ma!=10)) k[1]++;
        if(bi==3) k[2]+=2;
        if(bi==4) k[2]+=2,k[3]+=4;

        int ma2=mask^ma;
        if(ma2==13 || ma2==11 || ma2==14) ma2=7;
        if(ma2==9 || ma2==6 || ma2==12) ma2=3;
        if(ma2==10) ma2=5;
        if(ma2==2 || ma2==4 || ma2==8) ma2=1;
        // get boarder
        if(level>0) {
            int x,y;
            FOR(l,5){
                if(k[l]==0) continue;
                if(num-l<0) continue;
                if(ma2==0) x=0,y=0;
                else if(ma2==1) x=3,y=0;
                else if(ma2==5) x=6,y=0;
                else if(ma2==3) x=6,y=1;
                else if(ma2==7) x=9,y=2;
                else if(ma2==15) x=12,y=4;
                FOR(i,y+1) FOR(j,x-y*2+1) ret += dodp(level-1,num-l-(i+j),ma2) * k[l]*C[y][i] * C[x-i*2][j];
            }
        }
        else {
            FOR(l,5) ret += dodp(level-1,num-l,ma2) * k[l];
        }
    }

    return dpdp[level][num][mask]=(ret%=mo);
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstdlib>
#include <cstring>
#include <memory>
#include <cstdio>
#include <fstream>
#include <iostream>
#include <cmath>
#include <string>
#include <sstream>
#include <stack>
#include <queue>
#include <vector>
#include <set>
#include <map>
#include <algorithm>
using namespace std;

typedef signed long long ll;

#undef _P
#define _P(...) (void)printf(__VA_ARGS__)

#define FOR(x,to) for(x=0;x<to;x++)
#define ITR(x,c) for(__typeof(c.begin()) x=c.begin();x!=c.end();x++)
#define ZERO(a) memset(a,0,sizeof(a))
void _fill_int(int* p,int val,int rep) {int i;  FOR(i,rep) p[i]=val;}
void _fill_ll(ll* p,ll val,int rep) {int i; FOR(i,rep) p[i]=val;}
#define MINUS(a) _fill_int((int*)a,-1,sizeof(a)/4)
#define MINUSL(a) _fill_ll((ll*)a,-1LL,sizeof(a)/8)
ll GETi() { ll i;scanf("%lld",&i); return i;}
//-------------------------------------------------------

int N,K;
ll mo=1000000007;
ll dpdp[205][205][16];
const int CN=20;
ll C[CN][CN];

ll dodp(int level,int num,int mask) {
    int ma,i,j,k[5],l;
    if(num==0) return 1;
    if(num<0 || mask==0) return 0;
    if(dpdp[level][num][mask]!=-1) return dpdp[level][num][mask];
    /*
    if(mask==13 || mask==11 || mask==14) return dpdp[level][num][mask]=dodp(level,num,7); //used 1
    if(mask==9|| mask==6 || mask==12) return dpdp[level][num][mask]=dodp(level,num,3); //used 2
    if(mask==10) return dpdp[level][num][mask]=dodp(level,num,5); //used 2
    if(mask==2|| mask==4 || mask==8) return dpdp[level][num][mask]=dodp(level,num,1); //used 3
    */

    ll ret=0;
    FOR(ma,16) {
        if((mask & ma)!=ma) continue;

        //get whole block
        int bi=__builtin_popcount(ma);
        k[0]=k[1]=k[2]=k[3]=k[4]=0;
        k[bi]=1;
        if(bi==2 && (ma!=5) && (ma!=10)) k[1]++;
        if(bi==3) k[2]+=2;
        if(bi==4) k[2]+=2,k[3]+=4;

        // get boarder
        if(level>0) {
            int ma2=mask^ma;
            if(ma2==13 || ma2==11 || ma2==14) ma2=7;
            if(ma2==9 || ma2==6 || ma2==12) ma2=3;
            if(ma2==10) ma2=5;
            if(ma2==2 || ma2==4 || ma2==8) ma2=1;

            int x,y;
            FOR(l,5){
                if(k[l]==0) continue;
                if(num-l<0) continue;
                if(ma2==0) x=0,y=0;
                else if(ma2==1) x=3,y=0;
                else if(ma2==5) x=6,y=0;
                else if(ma2==3) x=6,y=1;
                else if(ma2==7) x=9,y=2;
                else if(ma2==15) x=12,y=4;
                FOR(i,y+1) FOR(j,x-y*2+1) ret += dodp(level-1,num-l-(i+j),ma2) * ((k[l]* C[y][i] * C[x-i*2][j])%mo);
            }
        }
        else {
            FOR(l,5) ret += (num==l) * k[l];
        }
    }

    return dpdp[level][num][mask]=(ret%=mo);
}

void solve() {
    int f,i,j,k,l, x,y;

    cin>>N>>K;
    FOR(x,CN) C[x][0]=C[x][x]=1;
    for(i=1;i<CN;i++) for(j=1;j<i;j++) C[i][j]=(C[i-1][j-1]+C[i-1][j])%mo;
    MINUSL(dpdp);

    ll ret=dodp(N,K,15);
    FOR(i,K) ret=(ret*(i+1))%mo;
    cout << ret << endl;
}

int main(int argc,char** argv){
    if(argc>1) freopen(argv[1], "r", stdin);
    solve();
    return 0;
}

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MOD = 1000000007;

int N, K;
int P[202][202][6][2];

void add(int& x, long long y)
{
    while (y >= MOD) y -= MOD;
    x += y;
    if (x >= MOD) x -= MOD;
}

int getDP(int size, int trng, int state, bool period)
{
    if (trng < 0) return 0;
    if (trng == 0) return 1;
    if (state == 4) return 0;
    if (size == 0 && period) return 0;

    int& now = P[size][trng][state][period];

    if (now != -1) return now;
    now = 0;

    if (period == false)
    {
        if (state == 0)
        {
            add(now, getDP(size, trng, 0, true));
            add(now, 4LL * getDP(size, trng - 1, 1, true));
            add(now, 4LL * getDP(size, trng - 1, 2, true));
            add(now, 4LL * getDP(size, trng - 2, 2, true));
            add(now, 8LL * getDP(size, trng - 2, 3, true));
            add(now, 4LL * getDP(size, trng - 3, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, 4LL * getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 4, 4, true));
            add(now, 2LL * getDP(size, trng - 2, 5, true));
        }
        else if (state == 1)
        {
            add(now, getDP(size, trng, 1, true));
            add(now, 2LL * getDP(size, trng - 1, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, 3LL * getDP(size, trng - 2, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 1, 5, true));
        }
        else if (state == 2)
        {
            add(now, getDP(size, trng, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
        else if (state == 3)
        {
            add(now, getDP(size, trng, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
        }
        else if (state == 5)
        {
            add(now, getDP(size, trng, 5, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
    }
    else
    {
        add(now, getDP(size - 1, trng, state, false));
        if (state == 0)
        {
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, getDP(size - 1, trng - total, 0, false));
                }
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 4 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 1)
        {
            for (int i = 1; i <= 3 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 2) add(now, 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 3) add(now, getDP(size - 1, trng - total, 1, false));
                }
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 3 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 2)
        {
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 2, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 2, false));
                }
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 2 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 3)
        {
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, getDP(size - 1, trng - total, 3, false));
                }
        }
        else if (state == 5)
        {
            for (int i = 1; i <= 2; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 3, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 3, false));
                }
        }
    }

    return now;
}

int main()
{
    cin >> N >> K;

    memset(P, -1, sizeof(P));

    int result = getDP(N, K, 0, false);
    for (int i = 1; i <= K; ++i)
        result = 1LL * result * i % MOD;

    cout << result << '\n';
}

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int MOD = 1000000007;

int N, K;
int P[202][202][6][2];

void add(int& x, long long y)
{
    while (y >= MOD) y -= MOD;
    x += y;
    if (x >= MOD) x -= MOD;
}

int getDP(int size, int trng, int state, bool period)
{
    if (trng < 0) return 0;
    if (trng == 0) return 1;
    if (state == 4) return 0;
    if (size == 0 && period) return 0;

    int& now = P[size][trng][state][period];

    if (now != -1) return now;
    now = 0;

    if (period == false)
    {
        if (state == 0)
        {
            add(now, getDP(size, trng, 0, true));
            add(now, 4LL * getDP(size, trng - 1, 1, true));
            add(now, 4LL * getDP(size, trng - 1, 2, true));
            add(now, 4LL * getDP(size, trng - 2, 2, true));
            add(now, 8LL * getDP(size, trng - 2, 3, true));
            add(now, 4LL * getDP(size, trng - 3, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, 4LL * getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 4, 4, true));
            add(now, 2LL * getDP(size, trng - 2, 5, true));
        }
        else if (state == 1)
        {
            add(now, getDP(size, trng, 1, true));
            add(now, 2LL * getDP(size, trng - 1, 2, true));
            add(now, getDP(size, trng - 1, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, 3LL * getDP(size, trng - 2, 3, true));
            add(now, 2LL * getDP(size, trng - 2, 4, true));
            add(now, getDP(size, trng - 3, 4, true));
            add(now, getDP(size, trng - 1, 5, true));
        }
        else if (state == 2)
        {
            add(now, getDP(size, trng, 2, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
        else if (state == 3)
        {
            add(now, getDP(size, trng, 3, true));
            add(now, getDP(size, trng - 1, 4, true));
        }
        else if (state == 5)
        {
            add(now, getDP(size, trng, 5, true));
            add(now, 2LL * getDP(size, trng - 1, 3, true));
            add(now, getDP(size, trng - 2, 4, true));
        }
    }
    else
    {
        add(now, getDP(size - 1, trng, state, false));
        if (state == 0)
        {
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, getDP(size - 1, trng - total, 0, false));
                }
            for (int i = 1; i <= 4 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 4 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, 6LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 3) add(now, 4LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 4) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 1)
        {
            for (int i = 1; i <= 3 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 2) add(now, 3LL * getDP(size - 1, trng - total, 1, false));
                    else if (i == 3) add(now, getDP(size - 1, trng - total, 1, false));
                }
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 3 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 0, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 2)
        {
            for (int i = 1; i <= 2 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 2, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 2, false));
                }
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * 2 - 2 * i)); ++j)
                {
                    int total = i, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, getDP(size - 1, trng - total, 0, false));
                }
        }
        else if (state == 3)
        {
            for (int i = 1; i <= 1 && i <= trng; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, getDP(size - 1, trng - total, 3, false));
                }
        }
        else if (state == 5)
        {
            for (int i = 1; i <= 2; ++i)
                for (int j = 0; j < (1 << (3 * i)); ++j)
                {
                    bool ok = true;
                    for (int k = 1; k <= i; ++k)
                        if (((j >> ((k - 1) * 3)) & 7) == 0)
                            ok = false;

                    if (!ok) continue;

                    int total = 0, aux = j;
                    while (aux)
                    {
                        ++total;
                        aux &= aux - 1;
                    }

                    if (trng < total) continue;

                    if (i == 1) add(now, 2LL * getDP(size - 1, trng - total, 3, false));
                    else if (i == 2) add(now, getDP(size - 1, trng - total, 3, false));
                }
        }
    }

    return now;
}

int main()
{
    cin >> N >> K;

    memset(P, -1, sizeof(P));

    int result = getDP(N, K, 0, false);
    for (int i = 1; i <= K; ++i)
        result = 1LL * result * i % MOD;

    cout << result << '\n';
}

#include <iostream>

using namespace std;

typedef long long int ll;

ll modulo=1000000007;

ll combi[10][10];

ll triangulo1(int n,int k);
ll triangulo2opuesto(int n,int k);
ll triangulo2(int n,int k);
ll triangulo3(int n,int k);
ll triangulo4(int n,int k);

ll cuadrado1(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=1 and kk<=k;kk++)
    mem=(mem+combi[1][kk]*triangulo1(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado2opuesto(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*triangulo2opuesto(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado2(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*triangulo2(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado3(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=3 and kk<=k;kk++)
    mem=(mem+combi[3][kk]*triangulo3(n-1,k-kk))%modulo;
  return mem;
}

ll cuadrado4(int n,int k)
{
  ll mem=0;
  for (int kk=0;kk<=4 and kk<=k;kk++)
    mem=(mem+combi[4][kk]*triangulo4(n-1,k-kk))%modulo;
  return mem;
}

ll memtriangulo1[201][201];

ll triangulo1(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 1;
    return 0;
  }
  ll &mem=memtriangulo1[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk=0;kk<=2 and kk<=k;kk++)
    mem=(mem+combi[2][kk]*cuadrado1(n,k-kk))%modulo;
  if (k==1) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo2opuesto[201][201];

ll triangulo2opuesto(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 2;
    if (k==2) return 1;
    return 0;
  }
  ll &mem=memtriangulo2opuesto[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk=0;kk<=4 and kk<=k;kk++)
    mem=(mem+combi[4][kk]*cuadrado2opuesto(n,k-kk))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  return mem;
}

ll memtriangulo2[201][201];

ll triangulo2(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 3;
    if (k==2) return 1;
    return 0;
  }
  ll &mem=memtriangulo2[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=1 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-kk1-kk2))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  if (k==1) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo3[201][201];

ll triangulo3(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 5;
    if (k==2) return 3+2;
    if (k==3) return 1;
    return 0;
  }
  ll &mem=memtriangulo3[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=2 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=6-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[2][kk1]*combi[6-2*kk1][kk2]*cuadrado3(n,k-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+2*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-1-kk1-kk2))%modulo;
  for (int kk=0;kk<=4 and kk+1<=k;kk++)
    mem=(mem+combi[4][kk]*cuadrado2opuesto(n,k-kk-1))%modulo;
  for (int kk=0;kk<=2 and kk+1<=k;kk++)
    mem=(mem+2*combi[2][kk]*cuadrado1(n,k-kk-1))%modulo;
  for (int kk=0;kk<=2 and kk+2<=k;kk++)
    mem=(mem+3*combi[2][kk]*cuadrado1(n,k-kk-2))%modulo;
  if (k==2) mem=(mem+2)%modulo;
  if (k==3) mem=(mem+1)%modulo;
  return mem;
}

ll memtriangulo4[201][201];

ll triangulo4(int n,int k)
{
  if (k==0) return 1;
  if (n==0) {
    if (k==1) return 8;
    if (k==2) return 6+8+2;
    if (k==3) return 4+4;
    if (k==4) return 1;
    return 0;
  }
  ll &mem=memtriangulo4[n][k];
  if (mem!=-1) return mem;
  mem=0;
  for (int kk1=0;kk1<=4 and kk1<=k;kk1++)
    for (int kk2=0;kk2<=8-2*kk1 and kk2<=k-kk1;kk2++)
      mem=(mem+combi[4][kk1]*combi[8-2*kk1][kk2]*cuadrado4(n,k-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=2 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=6-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+4*combi[2][kk1]*combi[6-2*kk1][kk2]*cuadrado3(n,k-1-kk1-kk2))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-2;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-2-kk1;kk2++)
      mem=(mem+4*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-2-kk1-kk2))%modulo;
  for (int kk=0;kk<=4 and kk<=k-2;kk++)
    mem=(mem+2*combi[4][kk]*cuadrado2opuesto(n,k-2-kk))%modulo;
  for (int kk1=0;kk1<=1 and kk1<=k-1;kk1++)
    for (int kk2=0;kk2<=4-2*kk1 and kk2<=k-1-kk1;kk2++)
      mem=(mem+4*combi[1][kk1]*combi[4-2*kk1][kk2]*cuadrado2(n,k-1-kk1-kk2))%modulo;
  for (int kk=0;kk<=2 and kk+2<=k;kk++)
    mem=(mem+8*combi[2][kk]*cuadrado1(n,k-kk-2))%modulo;
  for (int kk=0;kk<=2 and kk+3<=k;kk++)
    mem=(mem+4*combi[2][kk]*cuadrado1(n,k-kk-3))%modulo;
  if (k==2) mem=(mem+2)%modulo;
  if (k==3) mem=(mem+4)%modulo;
  if (k==4) mem=(mem+1)%modulo;
  return mem;
}

int main()
{
  {
    for (int n=0;n<10;n++)
      for (int k=0;k<=n;k++)
	if (k==0 or k==n) combi[n][k]=1;
	else combi[n][k]=(combi[n-1][k]+combi[n-1][k-1])%modulo;
  }
  for (int i=0;i<201;i++)
    for (int j=0;j<201;j++)
      memtriangulo1[i][j]=memtriangulo2opuesto[i][j]=
	memtriangulo2[i][j]=memtriangulo3[i][j]=memtriangulo4[i][j]=-1;
  int n,k;
  cin>>n>>k;
  ll sol=triangulo4(n,k);
  for (int i=1;i<=k;i++)
    sol=(sol*i)%modulo;
  cout<<sol<<endl;
}

#include <bits/stdc++.h>
using namespace std;
#define Rep(i, l, r) for (i = (l); i <= (r); i++)
#define Rev(i, r, l) for (i = (r); i >= (l); i--)
int CH, NEG;
template <typename TP>
inline void read(TP &ret)
{
	ret = NEG = 0;
	while (CH = getchar(), CH < '!')
		;
	if (CH == '-')
		NEG = true, CH = getchar();
	while (ret = ret * 10 + CH - '0', CH = getchar(), CH > '!')
		;
	if (NEG)
		ret = -ret;
}
template <typename TP>
inline void reads(TP &ret)
{
	while (ret = getchar(), ret < '!')
		;
	while (CH = getchar(), CH > '!')
		;
}

#include <cstring>

const int ansmod = 1000000007;
#define inc(a, b)        \
	{                    \
		a += b;          \
		if (a >= ansmod) \
			a -= ansmod; \
	}
#define maxn 210LL //n
#define maxk 210LL //k
#define maxs 16LL  //四位01状态
#define maxq 5LL   //四个象限
#define maxt 10LL  //一次转移最多增加8个三角形

int N, K;
int g[16][10][16] = {0};
int h[5][10][2][2][16] = {0};
int f[401][210][16] = {0};
int num[16];

//我们把第i层到第i+1层拆为两个步骤
//即从第i层转移到第i+0.5层(立放到平放)和第i+0.5层到i+1层(平放到立放)
//g[原始状态][增加几个三角形][到达目标状态]的方案数
//h[前i个象限][增加了几个三角形][第i*2个三角形是否使用][第1个三角形是否使用][此时的状态]
//(第i*2个也就是前i个象限中的最后一个三角形)
//h是用来求g的
//求得g后可以用来求f
//最后要乘k的阶乘,因为染色方案结果相同,顺序不同也算不同

int i, j, k, A, B, use, last, first, now1, now2, cnt, can, Time, ans;
int col[4] = {0};

int main()
{

		read(N), read(K);
	cout << N << ' ' << K << endl;
	Rep(A, 0, 16 - 1)
	{
		num[B = A] = 0;
		while (B)
			num[A] += (B & 1), B >>= 1;
		assert(num[A] == __builtin_popcount(A));
	}
	Rep(A, 0, 16 - 1)
	{
		memset(h, 0, sizeof h);
		h[1][0][0][0][A] = h[1][1][1][0][A | 1] = h[1][2][1][1][A | 1] =
		h[1][1][0][1][A | 1] = 1;
		if (!(A & 1))
			h[1][1][1][1][A | 1] = 1;
		Rep(i, 1, 3) Rep(use, 0, 8) Rep(last, 0, 1) Rep(first, 0, 1)
			Rep(B, 0, 16 - 1) if (h[i][use][last][first][B])
				Rep(now1, 0, 1) Rep(now2, 0, 1)
		{
			if (!now1 && !now2 && !((B >> i) & 1))
			//当前这个象限不使用三角形且这个象限本来就是空的
				inc(h[i + 1][use + 1][1][first][B | (1 << i)], h[i][use][last][first][B]);
				//那就添上一个大三角形
			inc(h[i + 1][use + now1 + now2][now2][first][B | ((now1 | now2) << i)],
			h[i][use][last][first][B]);
			if (!last && !now1)
				inc(h[i + 1][use + 1 + now2][now2][first][B | (1 << i) | (1 << (i - 1))],
				h[i][use][last][first][B]);
			//与上一个象限的三角形拼接成一个三角形添入
			if (!now1 && !now2 && !((B >> i) & 1) && !((B >> (i - 1)) & 1))
				inc(h[i + 1][use + 1][1][first | (i == 1)][B | (1 << i) | (1 << (i - 1))],
				h[i][use][last][first][B]);
			//如果两个相邻的象限都是空的,可以填一个很大的三角形 = =
		}
		Rep(use, 0, 8) Rep(B, 0, 16 - 1)
			inc(h[4][use + 1][1][1][B | 9], h[4][use][0][0][B]);
		Rep(use, 0, 8) Rep(B, 0, 16 - 1) if (!(B & 1) && !(B & 8))
			inc(h[4][use + 1][1][1][B | 9], h[4][use][0][0][B]);
		Rep(use, 0, 8) Rep(last, 0, 1) Rep(first, 0, 1) Rep(B, 0, 16 - 1)
			inc(g[A][use][B], h[4][use][last][first][B]);
	}
	Rep(A, 0, 16 - 1) Rep(B, 0, 16 - 1)
	{
		col[0] = col[1] = col[2] = col[3] = 0;
		cnt = 0;
		Rep(i, 0, 4 - 1)
			col[i] = ((A >> i) & 1),
			cnt += col[i];
		can = true;
		Rep(i, 0, 4 - 1) if ((B >> i) & 1)
		{
			if (col[i] || col[(i + 1) % 4])
				can = false;
			col[i] = col[(i + 1) % 4] = true;
			cnt++;
		}
		if (!can)
			continue;
		int K = 0;
		Rev(i, 4 - 1, 0)
			K = (K << 1) | col[i];
		f[0][cnt][K]++;
	}
	Rep(i, 0, 400 - 1) Rep(j, 0, 200) Rep(A, 0, 16 - 1) if (f[i][j][A]) if (i & 1)
	{
		//从奇数转移到偶数,统计的形状是立起来的正方形
		Rep(k, 0, 8)
			//所以这里最多有八个小三角形
			//但在转移时应该包括了两个三角形拼起来的情况
			Rep(B, 0, 16 - 1)
				inc(f[i + 1][j + k][B], (long long)f[i][j][A] * g[A][k][B] % ansmod);
	}
	else
	{
		//从偶数转移到奇数,统计的形状是平方的正方形
		Rep(k, 0, 16 - 1)
			//所以只用判断四个角是否有三角形即可
			inc(f[i + 1][j + num[k]][A | k], f[i][j][A]);
	}
	int ans = 0;
	Rep(A, 0, 16 - 1) inc(ans, f[2 * N][K][A]);
		Rep(i, 1, K)
			ans = (long long)ans * i % ansmod;
		printf("%d\n", ans);

	return 0;
}

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
#define sz(x) ((int)(x).size())
#define rep(i,l,r) for(int i=(l);i<(r);++i)
//------
const int N = 2e2 + 7;
const int MOD = 1e9 + 7;
int n, k, C[10][10], dp[N][N][5][3];
inline void inc(int &x, int y) {
	x += y;
	if (x >= MOD)
		x -= MOD;
}
inline int mul(int x, int y) {
	return 1ll * x * y % MOD;
}
const int tri[] = { 4, 3, 2, 1, 2 };
const int cor[] = { 4, 2, 1, 0, 0 };
int dfs(int lvl, int op, int qua, int type) {
	int &ret = dp[lvl][op][qua][type];
	if (~ret)
		return ret;
	ret = 0;
	if (type == 0) {
		int _tri = tri[qua];
		for (int i = 0; i <= min(_tri, op); ++i)
			inc(ret, mul(dfs(lvl - 1, op - i, qua, 2), C[_tri][i]));
	}
	if (type == 1) {
		if (lvl == 0)
			return ret = (op == 0);
		int _tri = tri[qua] << 1, _cor = cor[qua];
		for (int i = 0; i <= min(_cor, op); ++i)
			for (int j = 0; j <= min(op - i, _tri - (i << 1)); ++j)
				inc(ret, mul(dfs(lvl, op - i - j, qua, 0),
					mul(C[_cor][i], C[_tri - (i << 1)][j])));
	}
	if (type == 2) {
		inc(ret, dfs(lvl, op, qua, 1));
		if (qua == 0) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 1, 1), 4));
				inc(ret, mul(dfs(lvl, op - 1, 2, 1), 4));
			}
			if (op >= 2) {
				inc(ret, mul(dfs(lvl, op - 2, 2, 1), 4));
				inc(ret, mul(dfs(lvl, op - 2, 3, 1), 8));
				inc(ret, mul(dfs(lvl, op - 2, 4, 1), 2));
				if (op == 2)
					inc(ret, 2);
			}
			if (op >= 3) {
				inc(ret, mul(dfs(lvl, op - 3, 3, 1), 4));
				if (op == 3)
					inc(ret, 4);
			}
			if (op == 4)
				inc(ret, 1);
		}
		if (qua == 1) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 2, 1), 2));
				inc(ret, dfs(lvl, op - 1, 4, 1));
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
			}
			if (op >= 2) {
				inc(ret, mul(dfs(lvl, op - 2, 3, 1), 2));
				if (op == 2)
					inc(ret, 2);
			}
			if (op == 3)
				inc(ret, 1);
		}
		if (qua == 2) {
			if (op >= 1) {
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
				if (op == 1)
					inc(ret, 1);
			}
			if (op == 2)
				inc(ret, 1);
		}
		if (qua == 3 && op == 1)
			inc(ret, 1);
		if (qua == 4) {
			if (op >= 1)
				inc(ret, mul(dfs(lvl, op - 1, 3, 1), 2));
			if (op == 2)
				inc(ret, 1);
		}
	}
	return ret;
}
int fac(int n) {
	int ret = 1;
	rep(i, 2, n + 1)
		ret = 1ll * ret * i % MOD;
	return ret;
}
int main() {
	rep(i, 0, 10) {
		C[i][0] = C[i][i] = 1;
		rep(j, 1, i)
			C[i][j] = (C[i - 1][j - 1] + C[i - 1][j]) % MOD;
	}
	scanf("%d%d", &n, &k);
	memset(dp, -1, sizeof(dp));
	int ans = mul(dfs(n, k, 0, 2), fac(k));
	printf("%d", ans);
	return 0;
}