#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;
}

// 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 <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<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);
}

#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][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<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 <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;
}

#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 <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 <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 <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';
}

/*
 * 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 <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 <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;
}

#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;
}