#include using namespace std; #define rep(i, n) for(int i=0;i P; #define fi first #define sc second #define all(x) x.begin(), x.end() typedef pair P1; #define pb push_back #define mp make_pair #define INF 1000000000 typedef long long ll; const int mod = 1000000007; #define POSL(x, v) lower_bound(all(x), v) - x.begin() void dmp(vectorvi){ rep(i, vi.size()) cout << vi[i] << " "; cout << endl; } struct make{ int go[905][256]; vector>za; vectornorm(vectorvi){ mapM; int nxt = 1; rep(i, vi.size()){ if(vi[i] > 0){ if(M.find(vi[i]) == M.end()) M[vi[i]] = nxt++; vi[i] = M[vi[i]]; } } return vi; } bool ok(vectorvi){ int cnt[10]={}; stackS; rep(i, vi.size()){ if(vi[i] == 0) continue; if(S.size() && S.top() == vi[i]) S.pop(); else S.push(vi[i]); } if(S.size()) return 0; rep(i, vi.size()) cnt[vi[i]] ++; repn(i, 9){ if(cnt[i] != 0 && cnt[i] != 2) return 0; } return 1; } void rec(vectorvi, int n, vectorcur, int nxt){ if(vi.size() == n){ if(ok(vi) && vi == norm(vi)) za.pb(vi); return; } vi.pb(0); rec(vi, n, cur, nxt); vi.pop_back(); if(cur.size()){ vi.pb(cur.back()); cur.pop_back(); rec(vi, n, cur, nxt); cur.pb(vi.back()); vi.pop_back(); } vi.pb(nxt); cur.pb(nxt); rec(vi, n, cur, nxt+1); cur.pop_back(); vi.pop_back(); } }t[10]; struct uf{ int par[16]; void init() { rep(i, 16) par[i] = i; } int find(int x) { if(x == par[x]) return x; else return par[x] = find(par[x]); } void unite(int x, int y){ x = find(x); y = find(y); if(x == y) return; par[x] = y; } }kaede; void init(){ for(int n=4;n<=4;n++){ t[n].rec(vector(), n, vector(), 1); memset(t[n].go, -1, sizeof(t[n].go)); sort(all(t[n].za)); int cnt = t[n].za.size(); rep(i, cnt){ rep(j, (1<<(n-1))){ int deg[16] = {}; rep(k, n) deg[k] = !!t[n].za[i][k]; rep(q , n-1) if(((j >> q)&1)) deg[q]++, deg[q+1]++; bool bad = 0; //次数が2より大きかったらアウト rep(k, n) if(deg[k] > 2) bad = 1; if(bad) continue; vectornxt = t[n].za[i]; kaede.init(); //今頂点がoffのところには適当に大きい値を割り振る int id = 6; rep(q, n) if(nxt[q] == 0) nxt[q] = id++; rep(q , n-1) if(((j >> q)&1)) kaede.unite(nxt[q], nxt[q+1]); int mn[16]; rep(i, 16) mn[i] = INF; //連結成分ごとに一番小さいIDを使えば良い rep(q, 16) mn[kaede.find(q)] = min(mn[kaede.find(q)], q); //次数が1以上の連結成分を考え、そのうち次数 = 2のものは消える rep(q, n){ if(deg[q] == 0) nxt[q] = 0; else nxt[q] = mn[kaede.find(nxt[q])]; } bool ex[16] = {}, en[16] = {}; rep(q, n){ if(deg[q] == 1) ex[nxt[q]] = 1; else if(deg[q] == 2) en[nxt[q]] = 1; } int del = 0, zan = 0; rep(i, 16){ if(ex[i]) zan ++; else if(en[i]) del ++; } if(del == 0) { rep(q, n){ if(deg[q]%2 == 0) nxt[q] = 0; else nxt[q] = mn[kaede.find(nxt[q])]; } auto gt = t[n].norm(nxt); int A = POSL(t[n].za, gt); if(A == t[n].za.size() || t[n].za[A] != gt); else t[n].go[i][j] = A; } else if(del == 1 && zan == 0){ //end of cycle t[n].go[i][j] = t[n].za.size(); } } } } } ll way[10][105], ans[10][105]; int cnt[10][8]; template void add(T &a, T b){ a += b; if(a < 0) a += mod; if(a >= mod) a -= mod; } void sol(){ int n = 3; int sz = t[n+1].za.size()+1; rep(i, sz-1){ rep(j, (1<>x)&1)) { vt[x]++; vt[x+1]++; } rep(x, n+1) cnt[i][j] += !!vt[x]; } } way[0][0] ++; repn(i, (1<> nn; cout << ans[sz-1][nn] << endl; } int main(){ init(); sol(); }