import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Deque;
import java.util.function.Supplier;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.util.Collection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.function.Consumer;
import java.io.Closeable;
import java.io.Writer;
import java.util.ArrayDeque;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
    public static void main(String[] args) throws Exception {
        Thread thread = new Thread(null, new TaskAdapter(), "", 1 << 27);
        thread.start();
        thread.join();
    }

    static class TaskAdapter implements Runnable {
        @Override
        public void run() {
            InputStream inputStream = System.in;
            OutputStream outputStream = System.out;
            FastInput in = new FastInput(inputStream);
            FastOutput out = new FastOutput(outputStream);
            CYetAnotherNumberSequence solver = new CYetAnotherNumberSequence();
            solver.solve(1, in, out);
            out.close();
        }
    }

    static class CYetAnotherNumberSequence {
        public void solve(int testNumber, FastInput in, FastOutput out) {
            long n = in.readLong();
            int k = in.readInt();

            Modular mod = new Modular(1000000007);
            Power power = new Power(mod);

            int items = 200;
            int[] fib = new int[items];
            fib[0] = 1;
            fib[1] = 2;
            int[] a = new int[items];
            for (int i = 2; i < items; i++) {
                fib[i] = mod.plus(fib[i - 1], fib[i - 2]);
            }
            for (int i = 0; i < items; i++) {
                a[i] = mod.mul(fib[i], power.pow(i + 1, k));
                if (i > 0) {
                    a[i] = mod.plus(a[i], a[i - 1]);
                }
            }

            IntegerList seq = new IntegerList();
            seq.addAll(a);
            LinearRecurrenceSolver solver = LinearRecurrenceSolver.newSolverFromSequence(seq, mod);
            int ans = solver.solve(n - 1, seq);

            out.println(ans);
        }

    }

    static class Modular {
        int m;

        public int getMod() {
            return m;
        }

        public Modular(int m) {
            this.m = m;
        }

        public Modular(long m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public Modular(double m) {
            this.m = (int) m;
            if (this.m != m) {
                throw new IllegalArgumentException();
            }
        }

        public int valueOf(int x) {
            x %= m;
            if (x < 0) {
                x += m;
            }
            return x;
        }

        public int valueOf(long x) {
            x %= m;
            if (x < 0) {
                x += m;
            }
            return (int) x;
        }

        public int mul(int x, int y) {
            return valueOf((long) x * y);
        }

        public int plus(int x, int y) {
            return valueOf(x + y);
        }

        public int subtract(int x, int y) {
            return valueOf(x - y);
        }

        public String toString() {
            return "mod " + m;
        }

    }

    static class IntegerList implements Cloneable {
        private int size;
        private int cap;
        private int[] data;
        private static final int[] EMPTY = new int[0];

        public int[] getData() {
            return data;
        }

        public IntegerList(int cap) {
            this.cap = cap;
            if (cap == 0) {
                data = EMPTY;
            } else {
                data = new int[cap];
            }
        }

        public IntegerList(IntegerList list) {
            this.size = list.size;
            this.cap = list.cap;
            this.data = Arrays.copyOf(list.data, size);
        }

        public IntegerList() {
            this(0);
        }

        public void ensureSpace(int req) {
            if (req > cap) {
                while (cap < req) {
                    cap = Math.max(cap + 10, 2 * cap);
                }
                data = Arrays.copyOf(data, cap);
            }
        }

        private void checkRange(int i) {
            if (i < 0 || i >= size) {
                throw new ArrayIndexOutOfBoundsException("index " + i + " out of range");
            }
        }

        public int get(int i) {
            checkRange(i);
            return data[i];
        }

        public void add(int x) {
            ensureSpace(size + 1);
            data[size++] = x;
        }

        public void addAll(int[] x) {
            addAll(x, 0, x.length);
        }

        public void addAll(int[] x, int offset, int len) {
            ensureSpace(size + len);
            System.arraycopy(x, offset, data, size, len);
            size += len;
        }

        public void addAll(IntegerList list) {
            addAll(list.data, 0, list.size);
        }

        public void expandWith(int x, int len) {
            ensureSpace(len);
            while (size < len) {
                data[size++] = x;
            }
        }

        public void retain(int n) {
            if (n < 0) {
                throw new IllegalArgumentException();
            }
            if (n >= size) {
                return;
            }
            size = n;
        }

        public void set(int i, int x) {
            checkRange(i);
            data[i] = x;
        }

        public int size() {
            return size;
        }

        public int[] toArray() {
            return Arrays.copyOf(data, size);
        }

        public void clear() {
            size = 0;
        }

        public String toString() {
            return Arrays.toString(toArray());
        }

        public boolean equals(Object obj) {
            if (!(obj instanceof IntegerList)) {
                return false;
            }
            IntegerList other = (IntegerList) obj;
            return SequenceUtils.equal(data, 0, size - 1, other.data, 0, other.size - 1);
        }

        public int hashCode() {
            int h = 1;
            for (int i = 0; i < size; i++) {
                h = h * 31 + Integer.hashCode(data[i]);
            }
            return h;
        }

        public IntegerList clone() {
            IntegerList ans = new IntegerList();
            ans.addAll(this);
            return ans;
        }

    }

    static class SequenceUtils {
        public static boolean equal(int[] a, int al, int ar, int[] b, int bl, int br) {
            if ((ar - al) != (br - bl)) {
                return false;
            }
            for (int i = al, j = bl; i <= ar; i++, j++) {
                if (a[i] != b[j]) {
                    return false;
                }
            }
            return true;
        }

    }

    static class ModLinearFeedbackShiftRegister {
        private IntegerList cm;
        int m = -1;
        int dm;
        private IntegerList cn;
        private IntegerList buf;
        private IntegerList seq;
        private Modular mod;
        private Power pow;

        public ModLinearFeedbackShiftRegister(Modular mod, int cap) {
            cm = new IntegerList(cap + 1);
            cn = new IntegerList(cap + 1);
            seq = new IntegerList(cap + 1);
            buf = new IntegerList(cap + 1);
            cn.add(1);

            this.mod = mod;
            this.pow = new Power(mod);
        }

        public ModLinearFeedbackShiftRegister(Modular mod) {
            this(mod, 0);
        }

        private int estimateDelta() {
            int n = seq.size() - 1;
            int ans = 0;
            int[] cnData = cn.getData();
            int[] seqData = seq.getData();
            for (int i = 0, until = cn.size(); i < until; i++) {
                ans = mod.plus(ans, mod.mul(cnData[i], seqData[n - i]));
            }
            return ans;
        }

        public void add(int x) {
            x = mod.valueOf(x);
            int n = seq.size();

            seq.add(x);
            int dn = estimateDelta();
            if (dn == 0) {
                return;
            }

            if (m < 0) {
                cm.clear();
                cm.addAll(cn);
                dm = dn;
                m = n;

                cn.expandWith(0, n + 2);
                return;
            }

            int ln = cn.size() - 1;
            int len = Math.max(ln, n + 1 - ln);
            buf.clear();
            buf.addAll(cn);
            buf.expandWith(0, len + 1);

            int factor = mod.mul(dn, pow.inverseByFermat(dm));

            int[] bufData = buf.getData();
            int[] cmData = cm.getData();
            for (int i = n - m, until = n - m + cm.size(); i < until; i++) {
                bufData[i] = mod.subtract(bufData[i], mod.mul(factor, cmData[i - (n - m)]));
            }

            if (cn.size() < buf.size()) {
                IntegerList tmp = cm;
                cm = cn;
                cn = tmp;
                m = n;
                dm = dn;
            }
            {
                IntegerList tmp = cn;
                cn = buf;
                buf = tmp;
            }

        }

        public int length() {
            return cn.size() - 1;
        }

        public String toString() {
            return cn.toString();
        }

        public int codeAt(int i) {
            return mod.valueOf(-cn.get(i));
        }

    }

    static class Buffer<T> {
        private Deque<T> deque;
        private Supplier<T> supplier;
        private Consumer<T> cleaner;

        public Buffer(Supplier<T> supplier) {
            this(supplier, (x) -> {
            });
        }

        public Buffer(Supplier<T> supplier, Consumer<T> cleaner) {
            this(supplier, cleaner, 0);
        }

        public Buffer(Supplier<T> supplier, Consumer<T> cleaner, int exp) {
            this.supplier = supplier;
            this.cleaner = cleaner;
            deque = new ArrayDeque<>(exp);
        }

        public T alloc() {
            return deque.isEmpty() ? supplier.get() : deque.removeFirst();
        }

        public void release(T e) {
            cleaner.accept(e);
            deque.addLast(e);
        }

    }

    static class FastOutput implements AutoCloseable, Closeable {
        private StringBuilder cache = new StringBuilder(10 << 20);
        private final Writer os;

        public FastOutput(Writer os) {
            this.os = os;
        }

        public FastOutput(OutputStream os) {
            this(new OutputStreamWriter(os));
        }

        public FastOutput println(int c) {
            cache.append(c).append('\n');
            return this;
        }

        public FastOutput flush() {
            try {
                os.append(cache);
                os.flush();
                cache.setLength(0);
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
            return this;
        }

        public void close() {
            flush();
            try {
                os.close();
            } catch (IOException e) {
                throw new UncheckedIOException(e);
            }
        }

        public String toString() {
            return cache.toString();
        }

    }

    static class LinearRecurrenceSolver {
        Modular mod;
        IntegerList coe;
        IntegerList p;
        IntegerList remainder;
        Power pow;
        int n;

        private LinearRecurrenceSolver(IntegerList coe, Modular mod) {
            this.coe = coe;
            this.mod = mod;
            n = coe.size();
            pow = new Power(mod);
            remainder = new IntegerList(coe.size());
            p = new IntegerList(coe.size() + 1);
            for (int i = n - 1; i >= 0; i--) {
                p.add(mod.valueOf(-coe.get(i)));
            }
            p.add(1);
        }

        public static LinearRecurrenceSolver newSolverFromLinearRecurrence(IntegerList coe, Modular mod) {
            return new LinearRecurrenceSolver(coe, mod);
        }

        public static LinearRecurrenceSolver newSolverFromSequence(IntegerList seq, Modular mod) {
            ModLinearFeedbackShiftRegister lfsr = new ModLinearFeedbackShiftRegister(mod, seq.size());
            for (int i = 0; i < seq.size(); i++) {
                lfsr.add(seq.get(i));
            }
            IntegerList coes = new IntegerList(lfsr.length());
            for (int i = 1; i <= lfsr.length(); i++) {
                coes.add(lfsr.codeAt(i));
            }
            return newSolverFromLinearRecurrence(coes, mod);
        }

        private int solve(IntegerList a) {
            int ans = 0;
            remainder.expandWith(0, n);
            for (int i = 0; i < n; i++) {
                ans = mod.plus(ans, mod.mul(remainder.get(i), a.get(i)));
            }
            return ans;
        }

        public int solve(long k, IntegerList a) {
            if (k < a.size()) {
                return a.get((int) k);
            }
            Polynomials.module(k, p, remainder, pow);
            return solve(a);
        }

    }

    static class FastInput {
        private final InputStream is;
        private byte[] buf = new byte[1 << 13];
        private int bufLen;
        private int bufOffset;
        private int next;

        public FastInput(InputStream is) {
            this.is = is;
        }

        private int read() {
            while (bufLen == bufOffset) {
                bufOffset = 0;
                try {
                    bufLen = is.read(buf);
                } catch (IOException e) {
                    bufLen = -1;
                }
                if (bufLen == -1) {
                    return -1;
                }
            }
            return buf[bufOffset++];
        }

        public void skipBlank() {
            while (next >= 0 && next <= 32) {
                next = read();
            }
        }

        public int readInt() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            int val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

        public long readLong() {
            int sign = 1;

            skipBlank();
            if (next == '+' || next == '-') {
                sign = next == '+' ? 1 : -1;
                next = read();
            }

            long val = 0;
            if (sign == 1) {
                while (next >= '0' && next <= '9') {
                    val = val * 10 + next - '0';
                    next = read();
                }
            } else {
                while (next >= '0' && next <= '9') {
                    val = val * 10 - next + '0';
                    next = read();
                }
            }

            return val;
        }

    }

    static class ExtGCD {
        private long x;
        private long y;
        private long g;

        public long getX() {
            return x;
        }

        public long extgcd(long a, long b) {
            if (a >= b) {
                g = extgcd0(a, b);
            } else {
                g = extgcd0(b, a);
                long tmp = x;
                x = y;
                y = tmp;
            }
            return g;
        }

        private long extgcd0(long a, long b) {
            if (b == 0) {
                x = 1;
                y = 0;
                return a;
            }
            long g = extgcd0(b, a % b);
            long n = x;
            long m = y;
            x = m;
            y = n - m * (a / b);
            return g;
        }

    }

    static class Polynomials {
        public static Buffer<IntegerList> listBuffer = new Buffer<>(IntegerList::new, list -> list.clear());
        private static ExtGCD extGCD = new ExtGCD();

        public static int rankOf(IntegerList p) {
            int[] data = p.getData();
            int r = p.size() - 1;
            while (r >= 0 && data[r] == 0) {
                r--;
            }
            return Math.max(0, r);
        }

        public static void normalize(IntegerList list) {
            list.retain(rankOf(list) + 1);
        }

        public static void mul(IntegerList a, IntegerList b, IntegerList c, Modular mod) {
            int rA = rankOf(a);
            int rB = rankOf(b);
            c.clear();
            c.expandWith(0, rA + rB + 1);
            int[] aData = a.getData();
            int[] bData = b.getData();
            int[] cData = c.getData();
            for (int i = 0; i <= rA; i++) {
                for (int j = 0; j <= rB; j++) {
                    cData[i + j] = mod.plus(cData[i + j], mod.mul(aData[i], bData[j]));
                }
            }
        }

        public static void divide(IntegerList a, IntegerList b, IntegerList c, IntegerList remainder, Power pow) {
            Modular mod = pow.getModular();
            int rA = rankOf(a);
            int rB = rankOf(b);

            if (rA < rB) {
                c.clear();
                c.add(0);
                remainder.clear();
                remainder.addAll(a);
                return;
            }

            int rC = Math.max(0, rA - rB);
            c.clear();
            c.expandWith(0, rC + 1);
            remainder.clear();
            remainder.addAll(a);

            int[] bData = b.getData();
            int[] cData = c.getData();
            int[] rData = remainder.getData();

            if (extGCD.extgcd(b.get(rB), mod.getMod()) != 1) {
                throw new IllegalArgumentException();
            }
            int inv = mod.valueOf(extGCD.getX());
            for (int i = rA, j = rC; i >= rB; i--, j--) {
                if (rData[i] == 0) {
                    continue;
                }
                int factor = mod.mul(-rData[i], inv);
                cData[j] = mod.valueOf(-factor);
                for (int k = rB; k >= 0; k--) {
                    rData[k + j] = mod.plus(rData[k + j], mod.mul(factor, bData[k]));
                }
            }

            normalize(remainder);
        }

        public static void module(long k, IntegerList p, IntegerList remainder, Power pow) {
            int rP = rankOf(p);
            if (rP == 0) {
                remainder.clear();
                remainder.add(0);
                return;
            }

            IntegerList a = listBuffer.alloc();
            IntegerList c = listBuffer.alloc();

            module(k, a, p, c, remainder, rP, pow);

            listBuffer.release(a);
            listBuffer.release(c);
        }

        private static void module(long k, IntegerList a, IntegerList b, IntegerList c, IntegerList remainder, int rb, Power pow) {
            Modular mod = pow.getModular();
            if (k < rb) {
                remainder.clear();
                remainder.expandWith(0, (int) k + 1);
                remainder.set((int) k, 1);
                return;
            }
            module(k / 2, a, b, c, remainder, rb, pow);
            mul(remainder, remainder, a, mod);
            if (k % 2 == 1) {
                int ra = rankOf(a);
                a.expandWith(0, ra + 2);
                int[] aData = a.getData();
                for (int i = ra; i >= 0; i--) {
                    aData[i + 1] = aData[i];
                }
                aData[0] = 0;
            }
            divide(a, b, c, remainder, pow);
        }

    }

    static class Power {
        final Modular modular;

        public Modular getModular() {
            return modular;
        }

        public Power(Modular modular) {
            this.modular = modular;
        }

        public int pow(int x, int n) {
            if (n == 0) {
                return modular.valueOf(1);
            }
            long r = pow(x, n >> 1);
            r = modular.valueOf(r * r);
            if ((n & 1) == 1) {
                r = modular.valueOf(r * x);
            }
            return (int) r;
        }

        public int inverseByFermat(int x) {
            return pow(x, modular.m - 2);
        }

    }
}


import java.io.*;
import java.lang.reflect.Array;
import java.math.*;
import java.text.DecimalFormat;
import java.util.*;

public class Main {
    public static final int mod = 1000000007;
    private static int [] [] C;
    public static int add(int a,int b) {
        a += b;
        if (a >= mod) a -= mod;
        return a;
    }
    public static int mul(int a,int b){
        return (int)((a*(long)b)%mod);
    }

    private static void init(){
        int MAXK = 40;
        C = new int[MAXK+1][MAXK+1];
        for (int n = 0;n <= MAXK;n++){
            C[n][0] = C[n][n] = 1;
            for (int k = 1;k < n;k++)
                C[n][k] = add(C[n-1][k],C[n-1][k-1]);
        }
    }

    private static matrix buildMatrix(int K){
        matrix ret = new matrix(2*K+3);
        for (int i = 0;i <= K;i++) {
            int r = i+1,k = K - i;
            for (int j = 0;j <= k;j++) {
                int c = r + j;
                ret.A[r][c] = C[k][j];
            }
            for (int j = 0;j <= k;j++) {
                int c = r + j + K + 1;
                ret.A[r][c] = C[k][j];
            }
            for (int j = 1;j <= K+1;j++) {
                int rd = r + K+1;
                ret.A[rd][j] = ret.A[r][j];
            }

        }
        for (int i = 1;i < ret.n;i++)
            ret.A[0][i] = ret.A[1][i];
        ret.A[0][0] = 1;
        return ret;
    }

    private static int powmod(int x,int p) {
        if (p == 0) return 1;
        int y = 1;
        for (;p > 1;p >>= 1) {
            if (p%2 == 1) y = mul(x,y);
            x = mul(x,x);
        }
        return mul(x,y);
    }
    public static void main(String[] args) throws Exception{
        IO io = new IO(null,null);
        init();
        long n = io.getNextLong();
        int K = io.getNextInt();
        int S2 = add(1,powmod(2,K+1));
        if (n == 1)io.println(1);
        else {
            matrix mat = buildMatrix(K);
//            for (int i = 0;i < mat.n;i++)
//                System.err.println(Arrays.toString(mat.A[i]));
//            System.err.println("");
            int [] [] A = mat.exp(n-2);
            int [] B = new int[mat.n];
            B[0] = S2;
            for (int i = 0;i <= K;i++)
                B[i+1] = powmod(2,K-i + 1);
            for (int i = 0;i <= K;i++)
                B[i+K+2] = powmod(2,K-i);
//            for (int i = 0;i < mat.n;i++)
//                System.err.println(Arrays.toString(A[i]));
//            System.err.println("");
//            System.err.println(Arrays.toString(B));

            int [] C = new int[A.length];
            for (int i = 0;i < A.length;i++)
                for (int j = 0;j < A.length;j++)
                    C[i] = add(C[i],mul(A[i][j],B[j]));
//            System.err.println(Arrays.toString(C));
            io.println(C[0]);
        }
        io.close();
    }
}

class matrix{
    int [] [] A;
    int n;
    public matrix(int dim){
        A = new int[dim][dim];
        n = dim;
    }
    public void makeEye(){
        for (int i = 0;i < n;i++)
            for (int j = 0;j < n;j++)
                A[i][j] = (i == j) ? 1 : 0;
    }
    public matrix mul(matrix O) {
        matrix C = new matrix(n);
        for (int i = 0;i < n;i++)
            for (int j = 0;j < n;j++)
                for (int k = 0;k < n;k++)
                    C.A[i][j] = Main.add(C.A[i][j],Main.mul(A[i][k],O.A[k][j]));
        return C;
    }
    public int [] [] exp(long p) {
        matrix B = new matrix(n);
        matrix C = new matrix(n);
        C.makeEye();
        for (int i = 0;i < n;i++)
            for (int j = 0;j < n;j++)
                B.A[i][j] = A[i][j];

        if (p == 0) {
            B.makeEye();
            return B.A;
        }
        for (;p > 1;p >>= 1) {
            if (p%2 == 1) C = C.mul(B);
            B = B.mul(B);
        }
        return B.mul(C).A;
    }
}

class IO{
    private BufferedReader br;
    private StringTokenizer st;
    private PrintWriter writer;
    private String inputFile,outputFile;

    public boolean hasMore() throws IOException{
        if(st != null && st.hasMoreTokens()) return true;
        if(br != null && br.ready()) return true;
        return false;
    }
    public String getNext() throws FileNotFoundException, IOException{
        while(st == null || !st.hasMoreTokens()) st = new StringTokenizer(br.readLine());
        return st.nextToken();
    }

    public String getNextLine() throws FileNotFoundException, IOException{
        return br.readLine().trim();
    }

    public int getNextInt() throws FileNotFoundException, IOException{
        return Integer.parseInt(getNext());
    }
    public long getNextLong() throws FileNotFoundException, IOException{
        return Long.parseLong(getNext());
    }

    public void print(double x,int num_digits) throws  IOException{
        writer.printf("%." + num_digits + "f" ,x);
    }
    public void println(double x,int num_digits) throws  IOException{
        writer.printf("%." + num_digits + "f\n" ,x);
    }
    public void print(Object o) throws  IOException{
        writer.print(o.toString());
    }

    public void println(Object o) throws  IOException{
        writer.println(o.toString());
    }
    public IO(String x,String y) throws FileNotFoundException, IOException{
        inputFile = x;
        outputFile = y;
        if(x != null) br = new BufferedReader(new FileReader(inputFile));
        else br = new BufferedReader(new InputStreamReader(System.in));
        if(y != null) writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)));
        else writer = new PrintWriter(new OutputStreamWriter(System.out));
    }

    protected void close() throws IOException{
        br.close();
        writer.close();
    }
    public void outputArr(Object [] A) throws IOException{
        int L = A.length;
        for (int i = 0;i < L;i++) {
            if(i > 0) writer.print(" ");
            writer.print(A[i]);
        }
        writer.print("\n");
    }
}


import java.io.*;
import java.util.Arrays;

public class CF392C {

    final static long MOD = 1000000007;

    static long[][] mul(long[][] a, long[][] b) {
        long[][] c = new long[a.length][a.length];
        for (int i = 0; i < a.length; ++i) {
            for (int j = 0; j < a.length; ++j) {
                for (int k = 0; k < a.length; ++k) {
                    c[i][j] = (c[i][j] + a[i][k] * b[k][j]) % MOD;
                }
            }
        }
        return c;
    }

    static long[][] pow(long[][] a, long pow) {
        long[][] r = new long[a.length][a.length];
        for (int i = 0; i < a.length; ++i) {
            r[i][i] = 1;
        }
        while (pow > 0) {
            if (pow % 2 == 1) {
                r = mul(r, a);
            }
            pow /= 2;
            a = mul(a, a);
        }
        return r;
    }

    public static void solve(Input in, PrintWriter out) throws IOException {
        long n = in.nextLong();
        int k = in.nextInt() + 1;
        long[][] cs = new long[k + 1][k + 1];
        for (int i = 0; i < cs.length; ++i) {
            for (int j = 1; j < i; ++j) {
                cs[i][j] = (cs[i - 1][j - 1] + cs[i - 1][j]) % MOD;
            }
            cs[i][0] = cs[i][i] = 1;
        }
        long[][] a = new long[2 * k + 1][2 * k + 1];
        long[][] b = new long[2 * k + 1][2 * k + 1];
        long[][] c = new long[2 * k + 1][2 * k + 1];
        a[2 * k][2 * k] = b[2 * k][2 * k] = c[2 * k][2 * k] = 1;
        a[2 * k][2 * k - 1] = 1;
        for (int i = 0; i < k; ++i) {
            a[k + i][k + i] = 1;
            b[i][k + i] = 1;
            b[k + i][i] = 1;
            b[k + i][k + i] = 1;
            c[i][i] = 1;
            for (int j = 0; j <= i; ++j) {
                a[i][j] = cs[i][j];
                c[k + i][k + j] = cs[i][j];
            }
        }
        long[][] m = mul(c, mul(b, a));
//        long[] r = new long[2 * k + 1];
//        for (int i = 0; i < k; ++i) {
//            r[k + i] = 1;
//        }
//        r[0] = 1;
//        for (int it = 0; it < n; ++it) {
//            System.err.println(Arrays.toString(r));
//            long[] r1 = new long[2 * k + 1];
//            for (int i = 0; i < 2 * k + 1; ++i) {
//                for (int j = 0; j < 2 * k + 1; ++j) {
//                    r1[i] = (r1[i] + m[i][j] * r[j]) % MOD;
//                }
//            }
//            r = r1;
//        }
//        System.err.println(Arrays.toString(r));
        m = pow(m, n);
        long ans = m[2 * k][0];
        for (int i = 0; i < k; ++i) {
            ans = (ans + m[2 * k][k + i]) % MOD;
        }
        out.println(ans);
    }

    public static void main(String[] args) throws IOException {
        PrintWriter out = new PrintWriter(System.out);
        solve(new Input(new BufferedReader(new InputStreamReader(System.in))), out);
        out.close();
    }

    static class Input {
        BufferedReader in;
        StringBuilder sb = new StringBuilder();

        public Input(BufferedReader in) {
            this.in = in;
        }

        public Input(String s) {
            this.in = new BufferedReader(new StringReader(s));
        }

        public String next() throws IOException {
            sb.setLength(0);
            while (true) {
                int c = in.read();
                if (c == -1) {
                    return null;
                }
                if (" \n\r\t".indexOf(c) == -1) {
                    sb.append((char)c);
                    break;
                }
            }
            while (true) {
                int c = in.read();
                if (c == -1 || " \n\r\t".indexOf(c) != -1) {
                    break;
                }
                sb.append((char)c);
            }
            return sb.toString();
        }

        public int nextInt() throws IOException {
            return Integer.parseInt(next());
        }

        public long nextLong() throws IOException {
            return Long.parseLong(next());
        }

        public double nextDouble() throws IOException {
            return Double.parseDouble(next());
        }
    }
}


//package round791;
import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Queue;

public class F2 {
	InputStream is;
	FastWriter out;
	String INPUT = "";

	void solve()
	{
		int n = ni();
		boolean[][] g = new boolean[10][10];
		for(int m = ni();m > 0;m--){
			int x = ni(), y = ni();
			g[x][y] = g[y][x] = true;
		}
		for(int i = 0;i < 10;i++)g[i][i] = true;

		int[][] njs = new int[1<<9][10];
		for(int j = 0;j < 1<<9;j++) {
			for (int k = 0; k < 10; k++) {
				if (j << ~k >= 0) {
					int nj = j;
					for (int l = 0; l < 10; l++) {
						if (g[k][l]) {
							if (k > l) {
								nj |= 1 << l;
							}
						} else {
							nj &= ~(1 << l);
						}
					}
					njs[j][k] = nj;
				}
			}
		}

		long[] dp = new long[1<<9];
		dp[0] = 1;
		for(int i = 1;i <= n;i++){
			long[] ndp = new long[1<<9];
			for(int j = 0;j < 1<<9;j++){
				for(int k = 0;k < 10;k++){
					if (j << ~k >= 0) {
						int nj = njs[j][k];
						ndp[nj] += dp[j];
						if(ndp[nj] >= mod)ndp[nj] -= mod;
					}
				}
			}
			dp = ndp;
		}
		long ans = sum(dp) % mod;
		out.println(ans);
	}

	public static long sum(long... a){long ret = 0; for(long v : a)ret += v; return ret;}

	public static final int mod = 998244353;
	public static final int G = 3;

	// only 998244353
	public static long[] mul(long[] a, long[] b)
	{
		if(a.length == 0 && b.length == 0)return new long[0];
		if(a.length + b.length >= 300) {
			return Arrays.copyOf(NTTStockham998244353.convolve(a, b), a.length + b.length - 1);
		}else{
			return mulnaive(a, b);
		}
	}

	public static long[] mul(long[] a, long[] b, int lim)
	{
		if(a.length + b.length >= 300) {
			return Arrays.copyOf(NTTStockham998244353.convolve(a, b), lim);
		}else{
			return mulnaive(a, b, lim);
		}
	}

	//	public static final int mod = 1000000007;
	//	public static long[] mul(long[] a, long[] b)
	//	{
	//		if(Math.max(a.length, b.length) >= 3000){
	//			return Arrays.copyOf(NTTCRT.convolve(a, b, 3, mod), a.length+b.length-1);
	//		}else{
	//			return mulnaive(a, b);
	//		}
	//	}

	//	public static long[] mul(long[] a, long[] b, int lim)
	//	{
	//		if(Math.max(a.length, b.length) >= 3000){
	//			return Arrays.copyOf(NTTCRT.convolve(a, b, 3, mod), lim);
	//		}else{
	//			return mulnaive(a, b, lim);
	//		}
	//	}

	public static final long big = (Long.MAX_VALUE/mod/mod-1)*mod*mod;

	public static long[] mulnaive(long[] a, long[] b)
	{
		long[] c = new long[a.length+b.length-1];
		for(int i = 0;i < a.length;i++){
			for(int j = 0;j < b.length;j++){
				c[i+j] += a[i]*b[j];
				if(c[i+j] >= big)c[i+j] -= big;
			}
		}
		for(int i = 0;i < c.length;i++)c[i] %= mod;
		return c;
	}

	public static long[] mulnaive(long[] a, long[] b, int lim)
	{
		long[] c = new long[lim];
		for(int i = 0;i < a.length;i++){
			for(int j = 0;j < b.length && i+j < lim;j++){
				c[i+j] += a[i]*b[j];
				if(c[i+j] >= big)c[i+j] -= big;
			}
		}
		for(int i = 0;i < c.length;i++)c[i] %= mod;
		return c;
	}

	public static class NTTStockham998244353 {
		private static final int P = 998244353, mod = P, G = 3;
		private static long[] wps;

		public static long[] convolve(long[] a, long[] b)
		{
			int m = Math.max(2, Integer.highestOneBit(Math.max(a.length, b.length)-1)<<2);

			wps = new long[m];
			long unit = pow(G, (P-1)/m);
			wps[0] = 1;
			for(int p = 1;p < m;p++) {
				wps[p] = wps[p-1] * unit % mod;
			}

			long[] fa = go(a, m, false);
			long[] fb = a == b ? fa : go(b, m, false);
			for(int i = 0;i < m;i++){
				fa[i] = fa[i]*fb[i] % mod;
			}
			fa = go(fa, m, true);
			for(int i = 1, j = m-1;i < j;i++,j--) {
				long d = fa[i]; fa[i] = fa[j]; fa[j] = d;
			}
			return fa;
		}

		private static void fft(long[] X, long[] Y)
		{
			int s = 1;
			boolean eo = false;
			for(int n = X.length;n >= 4;n /= 2) {
				int m = n/2;
				for(int p = 0;p < m;p++) {
					long wp = wps[s*p];
					long wk = (wp<<32)/P;
					for(int q = 0;q < s;q++) {
						long a = X[q + s*(p+0)];
						long b = X[q + s*(p+m)];
						long ndsts = a + b;
						if(ndsts >= 2*P)ndsts -= 2*P;
						long T = a - b + 2*P;
						long Q = wk*T>>>32;
						Y[q + s*(2*p+0)] = ndsts;
						Y[q + s*(2*p+1)] = wp*T-Q*P&(1L<<32)-1;
					}
				}
				s *= 2;
				eo = !eo;
				long[] D = X; X = Y; Y = D;
			}
			long[] z = eo ? Y : X;
			for(int q = 0;q < s;q++) {
				long a = X[q + 0];
				long b = X[q + s];
				z[q+0] = (a+b) % P;
				z[q+s] = (a-b+2*P) % P;
			}
		}

		//	private static void fft(long[] X, long[] Y)
		//	{
		//		int s = 1;
		//		boolean eo = false;
		//		for(int n = X.length;n >= 4;n /= 2) {
		//			int m = n/2;
		//			for(int p = 0;p < m;p++) {
		//				long wp = wps[s*p];
		//				for(int q = 0;q < s;q++) {
		//					long a = X[q + s*(p+0)];
		//					long b = X[q + s*(p+m)];
		//					Y[q + s*(2*p+0)] = (a+b) % P;
		//					Y[q + s*(2*p+1)] = (a-b+P) * wp % P;
		//				}
		//			}
		//			s *= 2;
		//			eo = !eo;
		//			long[] D = X; X = Y; Y = D;
		//		}
		//		long[] z = eo ? Y : X;
		//		for(int q = 0;q < s;q++) {
		//			long a = X[q + 0];
		//			long b = X[q + s];
		//			z[q+0] = (a+b) % P;
		//			z[q+s] = (a-b+P) % P;
		//		}
		//	}

		private static long[] go(long[] src, int n, boolean inverse)
		{
			long[] dst = Arrays.copyOf(src, n);
			fft(dst, new long[n]);
			if(inverse){
				long in = invl(n);
				for(int i = 0;i < n;i++){
					dst[i] = dst[i] * in % mod;
				}
			}

			return dst;
		}

		private static long pow(long a, long n) {
			//		a %= mod;
			long ret = 1;
			int x = 63 - Long.numberOfLeadingZeros(n);
			for (; x >= 0; x--) {
				ret = ret*ret % mod;
				if (n<<~x<0)ret = ret*a%mod;
			}
			return ret;
		}

		private static long invl(long a) {
			long b = mod;
			long p = 1, q = 0;
			while (b > 0) {
				long c = a / b;
				long d;
				d = a;
				a = b;
				b = d % b;
				d = p;
				p = q;
				q = d - c * q;
			}
			return p < 0 ? p + mod : p;
		}
	}

	public static long C(int n, int r, int mod, int[][] fif) {
		if (n < 0 || r < 0 || r > n) return 0;
		return (long) fif[0][n] * fif[1][r] % mod * fif[1][n - r] % mod;
	}

	public static int[][] enumFIF(int n, int mod) {
		int[] f = new int[n + 1];
		int[] invf = new int[n + 1];
		f[0] = 1;
		for (int i = 1; i <= n; i++) {
			f[i] = (int) ((long) f[i - 1] * i % mod);
		}
		long a = f[n];
		long b = mod;
		long p = 1, q = 0;
		while (b > 0) {
			long c = a / b;
			long d;
			d = a;
			a = b;
			b = d % b;
			d = p;
			p = q;
			q = d - c * q;
		}
		invf[n] = (int) (p < 0 ? p + mod : p);
		for (int i = n - 1; i >= 0; i--) {
			invf[i] = (int) ((long) invf[i + 1] * (i + 1) % mod);
		}
		return new int[][]{f, invf};
	}

	public static class DJSet {
		public int[] upper;

		public DJSet(int n) {
			upper = new int[n];
			Arrays.fill(upper, -1);
		}

		public int root(int x) {
			return upper[x] < 0 ? x : (upper[x] = root(upper[x]));
		}

		public boolean equiv(int x, int y) {
			return root(x) == root(y);
		}

		public boolean unite(int x, int y) {
			x = root(x);
			y = root(y);
			if (x != y) {
				if (upper[y] < upper[x]) {
					int d = x;
					x = y;
					y = d;
				}
				upper[x] += upper[y];
				upper[y] = x;
			}
			return x == y;
		}

		public int count() {
			int ct = 0;
			for (int u : upper) if (u < 0) ct++;
			return ct;
		}

		public int[][] toBucket() {
			int n = upper.length;
			int[][] ret = new int[n][];
			int[] rp = new int[n];
			for (int i = 0; i < n; i++) if (upper[i] < 0) ret[i] = new int[-upper[i]];
			for (int i = 0; i < n; i++) {
				int r = root(i);
				ret[r][rp[r]++] = i;
			}
			return ret;
		}
	}

	void run() throws Exception
	{
		is = oj ? System.in : new ByteArrayInputStream(INPUT.getBytes());
		out = new FastWriter(System.out);

		long s = System.currentTimeMillis();
		solve();
		out.flush();
		tr(System.currentTimeMillis()-s+"ms");
	}

	public static void main(String[] args) throws Exception { new F2().run(); }

	private byte[] inbuf = new byte[1024];
	public int lenbuf = 0, ptrbuf = 0;

	private int readByte()
	{
		if(lenbuf == -1)throw new InputMismatchException();
		if(ptrbuf >= lenbuf){
			ptrbuf = 0;
			try { lenbuf = is.read(inbuf); } catch (IOException e) { throw new InputMismatchException(); }
			if(lenbuf <= 0)return -1;
		}
		return inbuf[ptrbuf++];
	}

	private boolean isSpaceChar(int c) { return !(c >= 33 && c <= 126); }
	private int skip() { int b; while((b = readByte()) != -1 && isSpaceChar(b)); return b; }

	private double nd() { return Double.parseDouble(ns()); }
	private char nc() { return (char)skip(); }

	private String ns()
	{
		int b = skip();
		StringBuilder sb = new StringBuilder();
		while(!(isSpaceChar(b))){ // when nextLine, (isSpaceChar(b) && b != ' ')
			sb.appendCodePoint(b);
			b = readByte();
		}
		return sb.toString();
	}

	private char[] ns(int n)
	{
		char[] buf = new char[n];
		int b = skip(), p = 0;
		while(p < n && !(isSpaceChar(b))){
			buf[p++] = (char)b;
			b = readByte();
		}
		return n == p ? buf : Arrays.copyOf(buf, p);
	}

	private int[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private long[] nal(int n)
	{
		long[] a = new long[n];
		for(int i = 0;i < n;i++)a[i] = nl();
		return a;
	}

	private char[][] nm(int n, int m) {
		char[][] map = new char[n][];
		for(int i = 0;i < n;i++)map[i] = ns(m);
		return map;
	}

	private int[][] nmi(int n, int m) {
		int[][] map = new int[n][];
		for(int i = 0;i < n;i++)map[i] = na(m);
		return map;
	}

	private int ni() { return (int)nl(); }

	private long nl()
	{
		long num = 0;
		int b;
		boolean minus = false;
		while((b = readByte()) != -1 && !((b >= '0' && b <= '9') || b == '-'));
		if(b == '-'){
			minus = true;
			b = readByte();
		}

		while(true){
			if(b >= '0' && b <= '9'){
				num = num * 10 + (b - '0');
			}else{
				return minus ? -num : num;
			}
			b = readByte();
		}
	}

	public static class FastWriter
	{
		private static final int BUF_SIZE = 1<<13;
		private final byte[] buf = new byte[BUF_SIZE];
		private final OutputStream out;
		private int ptr = 0;

		private FastWriter(){out = null;}

		public FastWriter(OutputStream os)
		{
			this.out = os;
		}

		public FastWriter(String path)
		{
			try {
				this.out = new FileOutputStream(path);
			} catch (FileNotFoundException e) {
				throw new RuntimeException("FastWriter");
			}
		}

		public FastWriter write(byte b)
		{
			buf[ptr++] = b;
			if(ptr == BUF_SIZE)innerflush();
			return this;
		}

		public FastWriter write(char c)
		{
			return write((byte)c);
		}

		public FastWriter write(char[] s)
		{
			for(char c : s){
				buf[ptr++] = (byte)c;
				if(ptr == BUF_SIZE)innerflush();
			}
			return this;
		}

		public FastWriter write(String s)
		{
			s.chars().forEach(c -> {
				buf[ptr++] = (byte)c;
				if(ptr == BUF_SIZE)innerflush();
			});
			return this;
		}

		private static int countDigits(int l) {
			if (l >= 1000000000) return 10;
			if (l >= 100000000) return 9;
			if (l >= 10000000) return 8;
			if (l >= 1000000) return 7;
			if (l >= 100000) return 6;
			if (l >= 10000) return 5;
			if (l >= 1000) return 4;
			if (l >= 100) return 3;
			if (l >= 10) return 2;
			return 1;
		}

		public FastWriter write(int x)
		{
			if(x == Integer.MIN_VALUE){
				return write((long)x);
			}
			if(ptr + 12 >= BUF_SIZE)innerflush();
			if(x < 0){
				write((byte)'-');
				x = -x;
			}
			int d = countDigits(x);
			for(int i = ptr + d - 1;i >= ptr;i--){
				buf[i] = (byte)('0'+x%10);
				x /= 10;
			}
			ptr += d;
			return this;
		}

		private static int countDigits(long l) {
			if (l >= 1000000000000000000L) return 19;
			if (l >= 100000000000000000L) return 18;
			if (l >= 10000000000000000L) return 17;
			if (l >= 1000000000000000L) return 16;
			if (l >= 100000000000000L) return 15;
			if (l >= 10000000000000L) return 14;
			if (l >= 1000000000000L) return 13;
			if (l >= 100000000000L) return 12;
			if (l >= 10000000000L) return 11;
			if (l >= 1000000000L) return 10;
			if (l >= 100000000L) return 9;
			if (l >= 10000000L) return 8;
			if (l >= 1000000L) return 7;
			if (l >= 100000L) return 6;
			if (l >= 10000L) return 5;
			if (l >= 1000L) return 4;
			if (l >= 100L) return 3;
			if (l >= 10L) return 2;
			return 1;
		}

		public FastWriter write(long x)
		{
			if(x == Long.MIN_VALUE){
				return write("" + x);
			}
			if(ptr + 21 >= BUF_SIZE)innerflush();
			if(x < 0){
				write((byte)'-');
				x = -x;
			}
			int d = countDigits(x);
			for(int i = ptr + d - 1;i >= ptr;i--){
				buf[i] = (byte)('0'+x%10);
				x /= 10;
			}
			ptr += d;
			return this;
		}

		public FastWriter write(double x, int precision)
		{
			if(x < 0){
				write('-');
				x = -x;
			}
			x += Math.pow(10, -precision)/2;
			//		if(x < 0){ x = 0; }
			write((long)x).write(".");
			x -= (long)x;
			for(int i = 0;i < precision;i++){
				x *= 10;
				write((char)('0'+(int)x));
				x -= (int)x;
			}
			return this;
		}

		public FastWriter writeln(char c){
			return write(c).writeln();
		}

		public FastWriter writeln(int x){
			return write(x).writeln();
		}

		public FastWriter writeln(long x){
			return write(x).writeln();
		}

		public FastWriter writeln(double x, int precision){
			return write(x, precision).writeln();
		}

		public FastWriter write(int... xs)
		{
			boolean first = true;
			for(int x : xs) {
				if (!first) write(' ');
				first = false;
				write(x);
			}
			return this;
		}

		public FastWriter write(long... xs)
		{
			boolean first = true;
			for(long x : xs) {
				if (!first) write(' ');
				first = false;
				write(x);
			}
			return this;
		}

		public FastWriter writeln()
		{
			return write((byte)'\n');
		}

		public FastWriter writeln(int... xs)
		{
			return write(xs).writeln();
		}

		public FastWriter writeln(long... xs)
		{
			return write(xs).writeln();
		}

		public FastWriter writeln(char[] line)
		{
			return write(line).writeln();
		}

		public FastWriter writeln(char[]... map)
		{
			for(char[] line : map)write(line).writeln();
			return this;
		}

		public FastWriter writeln(String s)
		{
			return write(s).writeln();
		}

		private void innerflush()
		{
			try {
				out.write(buf, 0, ptr);
				ptr = 0;
			} catch (IOException e) {
				throw new RuntimeException("innerflush");
			}
		}

		public void flush()
		{
			innerflush();
			try {
				out.flush();
			} catch (IOException e) {
				throw new RuntimeException("flush");
			}
		}

		public FastWriter print(byte b) { return write(b); }
		public FastWriter print(char c) { return write(c); }
		public FastWriter print(char[] s) { return write(s); }
		public FastWriter print(String s) { return write(s); }
		public FastWriter print(int x) { return write(x); }
		public FastWriter print(long x) { return write(x); }
		public FastWriter print(double x, int precision) { return write(x, precision); }
		public FastWriter println(char c){ return writeln(c); }
		public FastWriter println(int x){ return writeln(x); }
		public FastWriter println(long x){ return writeln(x); }
		public FastWriter println(double x, int precision){ return writeln(x, precision); }
		public FastWriter print(int... xs) { return write(xs); }
		public FastWriter print(long... xs) { return write(xs); }
		public FastWriter println(int... xs) { return writeln(xs); }
		public FastWriter println(long... xs) { return writeln(xs); }
		public FastWriter println(char[] line) { return writeln(line); }
		public FastWriter println(char[]... map) { return writeln(map); }
		public FastWriter println(String s) { return writeln(s); }
		public FastWriter println() { return writeln(); }
	}

	public void trnz(int... o)
	{
		for(int i = 0;i < o.length;i++)if(o[i] != 0)System.out.print(i+":"+o[i]+" ");
		System.out.println();
	}

	// print ids which are 1
	public void trt(long... o)
	{
		Queue<Integer> stands = new ArrayDeque<>();
		for(int i = 0;i < o.length;i++){
			for(long x = o[i];x != 0;x &= x-1)stands.add(i<<6|Long.numberOfTrailingZeros(x));
		}
		System.out.println(stands);
	}

	public void tf(boolean... r)
	{
		for(boolean x : r)System.out.print(x?'#':'.');
		System.out.println();
	}

	public void tf(boolean[]... b)
	{
		for(boolean[] r : b) {
			for(boolean x : r)System.out.print(x?'#':'.');
			System.out.println();
		}
		System.out.println();
	}

	public void tf(long[]... b)
	{
		if(INPUT.length() != 0) {
			for (long[] r : b) {
				for (long x : r) {
					for (int i = 0; i < 64; i++) {
						System.out.print(x << ~i < 0 ? '#' : '.');
					}
				}
				System.out.println();
			}
			System.out.println();
		}
	}

	public void tf(long... b)
	{
		if(INPUT.length() != 0) {
			for (long x : b) {
				for (int i = 0; i < 64; i++) {
					System.out.print(x << ~i < 0 ? '#' : '.');
				}
			}
			System.out.println();
		}
	}

	private boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	private void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.util.*;
import java.io.*;
import java.math.BigInteger;

// you can compare with output.txt and expected out
public class Round791F {
	MyPrintWriter out;
	MyScanner in;

//	final static long FIXED_RANDOM;
//	static {
//		FIXED_RANDOM = System.currentTimeMillis();
//	}
	final static String IMPOSSIBLE = "IMPOSSIBLE";
	final static String POSSIBLE = "POSSIBLE";
	final static String YES = "YES";
	final static String NO = "NO";
	final static long MOD = 998244353;

    private void initIO(boolean isFileIO) {
        if (System.getProperty("ONLINE_JUDGE") == null && isFileIO) {
        	try{
	            in = new MyScanner(new FileInputStream("input.txt"));
	            out = new MyPrintWriter(new FileOutputStream("output.txt"));
        	}
        	catch(FileNotFoundException e){
        		e.printStackTrace();
        	}
        }
        else{
    		in = new MyScanner(System.in);
    	    out = new MyPrintWriter(new BufferedOutputStream(System.out));
        }
    }

	public static void main(String[] args){
//		Scanner in = new Scanner(new BufferedReader(new InputStreamReader(System.in)));

		Round791F sol = new Round791F();
		sol.run();
    }

	private void run() {
		boolean isDebug = false;
		boolean isFileIO = true;
		boolean hasMultipleTests = false;

		initIO(isFileIO);

		int t = hasMultipleTests? in.nextInt() : 1;

	    for (int i = 1; i <= t; ++i) {
	    	int n = in.nextInt();
	    	int m = in.nextInt();
	    	int[][] uv = in.nextPairs(m);
	    	int[] u = uv[0];
	    	int[] v = uv[1];

	    	if(isDebug){
		    	out.printf("Test %d\n", i);
	    	}

			long ans = solve2(u, v, n);
			out.println(ans);

			//validate(u, v, n);

			if(isDebug)
				out.flush();
	    }

	    in.close();
	    out.close();
	}

	// wrong idea for the validator.. meh
	private void validate(int[] u, int[] v, int n) {
		TreeSet<String> set = new TreeSet<>();
		int[][] cmp = new int[RADIX][RADIX];
		for(int i=0; i<RADIX; i++) {
			for(int j=0; j<RADIX; j++) {
				cmp[i][j] = 0;
			}
		}
		for(int i=0; i<u.length; i++) {
			int small = Math.min(u[i], v[i]);
			int large = Math.max(u[i], v[i]);
			cmp[small][large] = -1;
			cmp[large][small] = 1;
		}
//		for(int i=0; i<RADIX; i++) {
//			for(int j=0; j<RADIX; j++) {
//				for(int k=0; k<RADIX; k++) {
//					if(cmp[i][j] == 1 && cmp[j][k] == 1)
//						cmp[i][k] = 1;
//					else if(cmp[i][j] == -1 && cmp[j][k] == -1)
//						cmp[i][k] = -1;
//				}
//			}
//		}

		Comparator<Character> comp = new Comparator<Character>() {
			@Override
			public int compare(Character o1, Character o2) {
				return cmp[o1-'0'][o2-'0'];
			}
		};

		BigInteger curr = BigInteger.ZERO;
		BigInteger limit = BigInteger.valueOf(RADIX).pow(n);
		StringBuilder sb = new StringBuilder();
		while(curr.compareTo(limit) < 0) {
			String s = curr.toString(RADIX);
			int padding = n-s.length();
			sb.setLength(0);
			for(int i=0; i<padding; i++)
				sb.append('0');
			sb.append(s);
			Character[] arr = new Character[n];
			for(int i=0; i<n; i++)
				arr[i] = sb.charAt(i);
			 Arrays.sort(arr, comp);
			// can't use sorting since comp is not transitive
			// actually, should make transitive

//			char[] arr = new char[n];
//			for(int i=0; i<n; i++)
//				arr[i] = sb.charAt(i);
//
//			for(int i=n-1; i>=0; i--) {
//				for(int j=0; j<i; j++) {
//					if(cmp[arr[j]-'0'][arr[j+1]-'0'] == 1) {
//						char temp = arr[j+1];
//						arr[j+1] = arr[j];
//						arr[j] = temp;
//					}
//				}
//			}

			sb.setLength(0);
//			sb.append(arr);
			for(int i=0; i<n; i++)
				sb.append(arr[i]);
			set.add(sb.toString());
			curr = curr.add(BigInteger.ONE);
		}
		out.println(set.size());
		out.println(set);

		// 4 3
		// 0 1
		// 0 2
		// 2 3

		// 0302 -> 0320 -> 0230

        // [0000, 0001, 0002, 0003, 0011, 0012, 0013, 0021, 0022, 0023, 0030, 0031, 0033,
		// 0111, 0112, 0113, 0121, 0122, 0123, 0130, 0131, 0133,
		// 0211, 0212, 0213, 0221, 0222, 0223, 0230, 0231, 0233,
		// 0300, 0301, 0302, 0303, 0311, 0312, 0313, 0330, 0331, 0333,
		// 1111, 1112, 1113, 1121, 1122, 1123, 1130, 1131, 1133, 1211,
		// 1212, 1213, 1221, 1222, 1223, 1230, 1231, 1233,
		// 1300, 1301, 1302, 1303, 1311, 1312, 1313, 1330, 1331, 1333,
		// 2111, 2112, 2113, 2121, 2122, 2123, 2130, 2131, 2133,
		// 2211, 2212, 2213, 2221, 2222, 2223, 2230, 2231, 2233,
		// 2300, 2301, 2302, 2303, 2311, 2312, 2313, 2330, 2331, 2333,
		// 3000, 3001, 3002, 3003, 3011, 3012, 3013, 3021, 3022, 3023, 3030, 3031, 3033,
		// 3111, 3112, 3113, 3121, 3122, 3123, 3130, 3131, 3133,
		// 3300, 3301, 3302, 3303, 3311, 3312, 3313, 3330, 3331, 3333]

		// when inserting j
		// X +
	}

	final int RADIX = 10;
	private long solve2(int[] u, int[] v, int n) {

		// 50000*2^10 = 5*10^7 = 50*10^6 = 100MB
		// why exceed?
		// dp[i][set] = # representatives in a[n-i..n-1] where elements in the set can move forward
		// long[][] dp = new long[n][1<<RADIX];
		long[] dp = new long[1<<RADIX];

		for(int j=0; j<RADIX; j++) {
			dp[1<<j] = 1;
		}

		int[][] cmp = new int[RADIX][RADIX];
		int m = u.length;
		for(int i=0; i<m; i++) {
			int small = Math.min(u[i], v[i]);
			int larger = Math.max(u[i], v[i]);
			cmp[small][larger] = -1;
			cmp[larger][small] = 1;
		}

		boolean[][] isValid = new boolean[1<<RADIX][RADIX];
		int[][] map = new int[1<<RADIX][RADIX];

		for(int mask=0; mask< 1<<RADIX; mask++) {
			for(int j=0; j<RADIX; j++) {
				boolean ok = true;
				int next = 1<<j;
				for(int k=0; k<RADIX; k++) {
					if( (1<<k & mask) == 0)
						continue;
					// k can come forward
					// case 1: j is incomparable to k
					// -> remove k from the set
					if(cmp[j][k] == 0) {
					}
					// case 2: j, k can be swapped and j is smaller
					else if(cmp[j][k] == -1) {
						next |= 1<<k;
					}
					// case 3: j, k can be swapped and j is larger -> not a representative
					else {
						ok = false;
					}
				}
				isValid[mask][j] = ok;
				map[mask][j] = next;
			}
		}

		// n*2^RADIX*RADIX = 5*10^4*10^3*10 = 5*10^8
		for(int i=n-2; i>=0; i--) {
			long[] next = new long[1<<RADIX];
			for(int mask=0; mask < 1<<RADIX; mask++) {
				for(int j=0; j<RADIX; j++) {
					if(!isValid[mask][j])
						continue;
					int mask2 = map[mask][j];
					long val = next[mask2] + dp[mask];
					next[mask2] = val < MOD? val: val-MOD;
				}
			}
			dp = next;
		}

		long sum = 0;
		for(int mask=0; mask < 1<<RADIX; mask++)
			sum += dp[mask]; // < Integer.MAX_VALUE * 10^3
		return sum%MOD;
	}

	private long solve(int[] u, int[] v, int n) {
		int m = u.length;
		// S = [0, 10^n]
		// find # of equivalance classes S/~
		// base: swap uj and vj if they are adjacent digits

		// 10^n
		// (0, 1)

		// num[i] = # nums ending in i
		long[] num = new long[RADIX];
		for(int i=0; i<RADIX; i++)
			num[i] = 1;

		// multipliers[i][j] = contributions from num[i] when j is appended
		long[][] multipliers = new long[RADIX][RADIX];
		for(int i=0; i<RADIX; i++) {
			for(int j=0; j<RADIX; j++) {
				multipliers[i][j] = 1;
			}
		}

		for(int i=0; i<m; i++) {
			int min = Math.min(u[i], v[i]);
			int max = Math.max(u[i], v[i]);
			multipliers[max][min] = 0;
		}

		// xxxx0 + 1 -> xxxx01 * (1/2) + xxxx10 * (1/2)
		// yyyy1

		// (1/2) + (1/2) = 1
		// 2* + 2* = 1

		// string made of (0, 1)
		// -> different iff it has diff # of 0 or diff # of 1

		// (0, 1) (1, 2)
		// 0000000022222222
		// 0 and 2 can't swap
		// 021

		// xxxx0 + 0 -> k
		// xxxx0 + 1 -> k

		// xxxx1 + 0 -> X
		//

		int temp  =1;

		for(int i=1; i<n; i++) {
			long[] num2 = new long[RADIX];
			for(int j=0; j<RADIX; j++) {
				for(int k=0; k<RADIX; k++) {
					num2[j] += num[k]*multipliers[j][k] % MOD;
				}
				num2[j] %= MOD;
			}
			num = num2;
		}

		long sum = 0;
		for(int i=0; i<RADIX; i++)
			sum += num[i];

		return sum%MOD;
	}

	static long pow(int a, int k, long p) {
		long m = k;
		long ans = 1;

		// curr = k^(2^i)
		long curr = a;

		// k^(2x+1) = (k^x)^2 * k
		while(m > 0) {
			if( (m&1) == 1 ) {
				ans *= curr;
				ans %= p;
			}
			m >>= 1;
			curr *= curr;
			curr %= p;
		}
		return ans;
	}

	// computes a^(p-2)
	static long inverse(int a, long p) {
		return pow(a, (int)(p-2), p);
	}

	public static class MyScanner {
		BufferedReader br;
		StringTokenizer st;

		// 32768?
		public MyScanner(InputStream is, int bufferSize) {
			br = new BufferedReader(new InputStreamReader(is), bufferSize);
		}

		public MyScanner(InputStream is) {
			br = new BufferedReader(new InputStreamReader(is));
			// br = new BufferedReader(new InputStreamReader(System.in));
			// br = new BufferedReader(new InputStreamReader(new FileInputStream("input.txt")));
		}

		public void close() {
			try {
				br.close();
			} catch (IOException e) {
				e.printStackTrace();
			}

		}

		String next() {
			while (st == null || !st.hasMoreElements()) {
				try {
					st = new StringTokenizer(br.readLine());
				} catch (IOException e) {
					e.printStackTrace();
				}
			}
			return st.nextToken();
		}

		int nextInt() {
			return Integer.parseInt(next());
		}

		long nextLong() {
			return Long.parseLong(next());
		}

		double nextDouble() {
			return Double.parseDouble(next());
		}

		String nextLine(){
			String str = "";
			try {
				str = br.readLine();
			} catch (IOException e) {
				e.printStackTrace();
			}
			return str;
		}

		int[][] nextTreeEdges(int n, int offset){
			int[][] e = new int[n-1][2];
			for(int i=0; i<n-1; i++){
				e[i][0] = nextInt()+offset;
				e[i][1] = nextInt()+offset;
			}
			return e;
		}

		int[][] nextMatrix(int n, int m) {
			return nextMatrix(n, m, 0);
		}

		int[][] nextMatrix(int n, int m, int offset) {
			int[][] mat = new int[n][m];
			for(int i=0; i<n; i++) {
				for(int j=0; j<m; j++) {
					mat[i][j] = nextInt()+offset;
				}
			}
			return mat;
		}

		int[][] nextPairs(int n){
			return nextPairs(n, 0);
		}

		int[][] nextPairs(int n, int offset) {
			int[][] xy = new int[2][n];
			for(int i=0; i<n; i++) {
				xy[0][i] = nextInt() + offset;
				xy[1][i] = nextInt() + offset;
			}
			return xy;
		}

		int[][] nextGraphEdges(){
			return nextGraphEdges(0);
		}

		int[][] nextGraphEdges(int offset) {
			int m = nextInt();
			int[][] e = new int[m][2];
			for(int i=0; i<m; i++){
				e[i][0] = nextInt()+offset;
				e[i][1] = nextInt()+offset;
			}
			return e;
		}

		int[] nextIntArray(int len) {
			return nextIntArray(len, 0);
		}
		int[] nextIntArray(int len, int offset){
	    	int[] a = new int[len];
			for(int j=0; j<len; j++)
	    		a[j] = nextInt()+offset;
	    	return a;
		}

		long[] nextLongArray(int len) {
			return nextLongArray(len, 0);
		}
		long[] nextLongArray(int len, int offset){
	    	long[] a = new long[len];
			for(int j=0; j<len; j++)
	    		a[j] = nextLong()+offset;
	    	return a;
		}
	}

	public static class MyPrintWriter extends PrintWriter{
		public MyPrintWriter(OutputStream os) {
			super(os);
		}

		public void printlnAns(boolean ans) {
			if(ans)
				println(YES);
			else
				println(NO);
		}

		public void printAns(long[] arr){
			if(arr != null && arr.length > 0){
				print(arr[0]);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]);
				}
			}
		}
		public void printlnAns(long[] arr){
			printAns(arr);
			println();
		}

		public void printAns(int[] arr){
			if(arr != null && arr.length > 0){
				print(arr[0]);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]);
				}
			}
		}
		public void printlnAns(int[] arr){
			printAns(arr);
			println();
		}

		public <T> void printAns(ArrayList<T> arr){
			if(arr != null && arr.size() > 0){
				print(arr.get(0));
				for(int i=1; i<arr.size(); i++){
					print(" ");
					print(arr.get(i));
				}
			}
		}
		public <T> void printlnAns(ArrayList<T> arr){
			printAns(arr);
			println();
		}

		public void printAns(int[] arr, int add){
			if(arr != null && arr.length > 0){
				print(arr[0]+add);
				for(int i=1; i<arr.length; i++){
					print(" ");
					print(arr[i]+add);
				}
			}
		}
		public void printlnAns(int[] arr, int add){
			printAns(arr, add);
			println();
		}

		public void printAns(ArrayList<Integer> arr, int add) {
			if(arr != null && arr.size() > 0){
				print(arr.get(0)+add);
				for(int i=1; i<arr.size(); i++){
					print(" ");
					print(arr.get(i)+add);
				}
			}
		}

		public void printlnAns(ArrayList<Integer> arr, int add){
			printAns(arr, add);
			println();
		}

		public void printlnAnsSplit(long[] arr, int split){
			if(arr != null){
				for(int i=0; i<arr.length; i+=split){
					print(arr[i]);
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr[j]);
					}
					println();
				}
			}
		}

		public void printlnAnsSplit(int[] arr, int split){
			if(arr != null){
				for(int i=0; i<arr.length; i+=split){
					print(arr[i]);
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr[j]);
					}
					println();
				}
			}
		}

		public <T> void printlnAnsSplit(ArrayList<T> arr, int split){
			if(arr != null && !arr.isEmpty()){
				for(int i=0; i<arr.size(); i+=split){
					print(arr.get(i));
					for(int j=i+1; j<i+split; j++){
						print(" ");
						print(arr.get(j));
					}
					println();
				}
			}
		}
	}

	static private void permutateAndSort(int[] a) {
		int n = a.length;
		Random R = new Random(System.currentTimeMillis());
		for(int i=0; i<n; i++) {
			int t = R.nextInt(n-i);
			int temp = a[n-1-i];
			a[n-1-i] = a[t];
			a[t] = temp;
		}
		Arrays.sort(a);
	}

	static private int[][] constructChildren(int n, int[] parent, int parentRoot){
		int[][] childrens = new int[n][];

		int[] numChildren = new int[n];
		for(int i=0; i<parent.length; i++) {
			if(parent[i] != parentRoot)
				numChildren[parent[i]]++;
		}

		for(int i=0; i<n; i++) {
			childrens[i] = new int[numChildren[i]];
		}

		int[] idx = new int[n];
		for(int i=0; i<parent.length; i++) {
			if(parent[i] != parentRoot)
				childrens[parent[i]][idx[parent[i]]++] = i;
		}

		return childrens;
	}

	static private int[][][] constructDirectedNeighborhood(int n, int[][] e){
		int[] inDegree = new int[n];
		int[] outDegree = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			outDegree[u]++;
			inDegree[v]++;
		}

		int[][] inNeighbors = new int[n][];
		int[][] outNeighbors = new int[n][];
		for(int i=0; i<n; i++) {
			inNeighbors[i] = new int[inDegree[i]];
			outNeighbors[i] = new int[outDegree[i]];
		}

		int[] inIdx = new int[n];
		int[] outIdx = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			outNeighbors[u][outIdx[u]++] = v;
			inNeighbors[v][inIdx[v]++] = u;
		}

		return new int[][][] {inNeighbors, outNeighbors};
	}

	static private int[][] constructNeighborhood(int n, int[][] e) {
		int[] degree = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			degree[u]++;
			degree[v]++;
		}

		int[][] neighbors = new int[n][];
		for(int i=0; i<n; i++)
			neighbors[i] = new int[degree[i]];

		int[] idx = new int[n];
		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			neighbors[u][idx[u]++] = v;
			neighbors[v][idx[v]++] = u;
		}

		return neighbors;
	}

	static private void makeDotUndirected(int[][] e) {
		MyPrintWriter out2 = null;
		 try {
			out2 = new MyPrintWriter(new FileOutputStream("graph.dot"));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		out2.println("strict graph {");
		for(int i=0; i<e.length; i++){
			out2.println(e[i][0] + "--" + e[i][1] + ";");
		}
		out2.println("}");
		out2.close();
	}

	static private void makeDotDirected(int[][] e) {
		MyPrintWriter out2 = null;
		 try {
			out2 = new MyPrintWriter(new FileOutputStream("graph.dot"));
		} catch (FileNotFoundException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
		out2.println("strict digraph {");
		for(int i=0; i<e.length; i++){
			out2.println(e[i][0] + "->" + e[i][1] + ";");
		}
		out2.println("}");
		out2.close();
	}

}


import java.util.Scanner;

public class E {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int k = sc.nextInt();
		int[][]a = new int[n][n];
		int[][]dp = new int[1 << n][1 << n];
		for (int i = 1; i <= m; i++) {
			int v1 = sc.nextInt();
			int v2 = sc.nextInt();
			v1--;
			v2--;
			a[v1][v2] = a[v2][v1] = 1;
			dp[(1 << v1) | (1 << v2)][(1 << v1) | (1 << v2)] = 1;
		}
		for (int mask = 0; mask < (1 << n); mask++) {
			for (int subm = mask; subm != 0; subm = ((subm-1) & mask)) {
				if (dp[mask][subm]==0)
					continue;
				for (int i = 0; i < n; i++) {
					if ((mask & (1 << i)) != 0) {
						for (int j = 0; j < n; j++) {
							if ((mask & (1 << j))==0 && a[i][j]==1) {
								int new_subm = (subm | (1 << j));
								if ((subm & (1 << i)) != 0)
									new_subm ^= (1 << i);
								int q = (1 << n)-(1 << (j+1));
								if ((new_subm & q) != 0)
										continue;
								dp[mask | (1 << j)][new_subm] += dp[mask][subm];
							}
						}
					}
				}
			}
		}
		int ans = 0;
		for (int mask = 0; mask < (1 << n); mask++) {
			if (Integer.bitCount(mask)==k)
				ans += dp[(1 << n)-1][mask];
		}
		System.out.println(ans);
	}

}


import java.util.*;

public class E {
	public static void main(String[] args) {
		Scanner s = new Scanner(System.in);
		int n = s.nextInt(), m = s.nextInt(), k = s.nextInt();
		int[][] a = new int[m][];
		int[][] count = new int[1 << n][1 << n];
		for (int i = 0; i < m; ++i) {
			int u = s.nextInt() - 1, v = s.nextInt() - 1;
			a[i] = new int[] { u, v };
			count[bit(u) | bit(v)][bit(u) | bit(v)] = 1;
		}
		int result = 0;
		for (int used = 0; used < bit(n); ++used) {
			for (int deadends = 0; deadends < bit(n); ++deadends) {
				int c = Integer.bitCount(deadends);
				if (c > 1 && count[used][deadends] > 1) {
					count[used][deadends] /= c;
				}
				if (used == bit(n) - 1 && c == k) {
					result += count[used][deadends];
				}
				for (int i = 0; i < m; ++i) {
					int u = a[i][0], v = a[i][1];
					int ut = used, dt = deadends;
					if (isUsed(u, used) ^ isUsed(v, used)) {
						if (isUsed(u, used)) {
							ut = add(v, ut);
							if (isUsed(u, dt)) {
								dt = remove(u, dt);
							}
							dt = add(v, dt);
						} else {
							ut = add(u, ut);
							if (isUsed(v, dt)) {
								dt = remove(v, dt);
							}
							dt = add(u, dt);
						}
						count[ut][dt] += count[used][deadends];
					}
				}
			}
		}
		System.out.println(result);
	}

	private static int remove(int v, int dt) {
		return dt ^ bit(v);
	}

	private static int add(int u, int dt) {
		return dt | bit(u);
	}

	private static boolean isUsed(int u, int dt) {
		return (dt & bit(u)) > 0;
	}

	private static int bit(int v) {
		return 1 << v;
	}

}


import java.io.*;
import java.util.*;
import java.math.*;

public class cfD implements Runnable {
	private final boolean useStandardIO = true;
	private final String inFile = "segments.in";
	private final String outFile = "segments.out";

	int n, m, k;
	int[][] c, aa;

	int dp[][][];
	boolean[][][] was;

	int go(int m1, int m2, int need) {
		if (was[need][m1][m2])
			return dp[need][m1][m2];
		int res = 0;
		int have = Integer.bitCount(m1);
		int cur = Integer.bitCount(m2);
		if (m2 == 0) {
			if (have == need)
				res = 1;
		} else {
			int[] a1 = new int[have], a2 = new int[cur];
			int j = 0;
			for (int i = 0; i < n; ++i)
				if ((m1 & (1 << i)) != 0)
					a1[j++] = i;
			j = 0;
			for (int i = 0; i < n; ++i)
				if ((m2 & (1 << i)) != 0)
					a2[j++] = i;
			int tot = 1;
			for (int i = 0; i < cur; ++i)
				tot *= (have + 1);
			for (int mask = 1; mask < tot; ++mask) {
				int x = mask;
				int taken = 0, takenMask = 0, newLeaves = 0, newMask = 0;
				boolean ok = true;
				for (j = 0; j < cur; ++j) {
					int y = x % (have + 1);
					x /= (have + 1);
					if (y == 0)
						continue;
					--y;
					if (c[a1[y]][a2[j]] == 0) {
						ok = false;
						break;
					}
					if ((takenMask & (1 << y)) == 0) {
						++taken;
						takenMask |= (1 << y);
					}
					++newLeaves;
					newMask |= (1 << a2[j]);
				}
				if (!ok || newMask == 0)
					continue;
				int old = have - taken;
				if (m1 == 1 && newLeaves < 2)
					++old;
				if (need - old >= 0)
					res += go(newMask, m2 ^ newMask, need - old);
			}
		}

		was[need][m1][m2] = true;
		return dp[need][m1][m2] = res;
	}

	private void solve() throws IOException {
		n = nextInt();
		m = nextInt();
		k = nextInt();
		c = new int[n][n];
		for (int i = 0; i < m; ++i) {
			int x = nextInt() - 1, y = nextInt() - 1;
			c[x][y] = c[y][x] = 1;
		}

		dp = new int[k + 1][1 << n][1 << n];
		was = new boolean[k + 1][1 << n][1 << n];
		writer.print(go(1, (1 << n) - 2, k));
	}

	public static void main(String[] args) {
		new cfD().run();
	}

	BufferedReader reader;
	StringTokenizer tokenizer;
	PrintWriter writer;

	public void run() {
		try {
			Locale.setDefault(Locale.US);
			if (useStandardIO)
				reader = new BufferedReader(new InputStreamReader(System.in));
			else
				reader = new BufferedReader(new FileReader(inFile));
			tokenizer = null;
			if (useStandardIO)
				writer = new PrintWriter(System.out);
			else
				writer = new PrintWriter(new FileWriter(outFile));
			solve();
			reader.close();
			writer.close();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		}
	}

	int nextInt() throws IOException {
		return Integer.parseInt(nextToken());
	}

	long nextLong() throws IOException {
		return Long.parseLong(nextToken());
	}

	double nextDouble() throws IOException {
		return Double.parseDouble(nextToken());
	}

	BigInteger nextBigInteger() throws IOException {
		return new BigInteger(nextToken());
	}

	String nextToken() throws IOException {
		while (tokenizer == null || !tokenizer.hasMoreTokens()) {
			tokenizer = new StringTokenizer(reader.readLine());
		}
		return tokenizer.nextToken();
	}
}


import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;

/**
 * Created by IntelliJ IDEA.
 * User: piyushd
 * Date: 1/7/11
 * Time: 12:04 AM
 * To change this template use File | Settings | File Templates.
 */
public class DeadEnds {

	int N, M, K;
	int[][] graph;
	long[][] res;

	long solve(int mask, int leaf, int n, int k){
		if(k < 2) return 0;
		if(res[mask][leaf] != -1) return res[mask][leaf];

		if(n == 2){

			int x = -1, y = -1;
			for(int i = 0; i < N; i++) if((mask & (1<<i)) > 0){
				if(x == -1) x = i; else y = i;
			}

			return res[mask][leaf] = graph[x][y];
		}

		long ans = 0;
		for(int i = 0; i < N; i++){
			if((leaf & (1<<i)) > 0){
				for(int j = 0; j < N; j++){
					if((mask & (1<<j)) > 0 && (leaf & (1<<j)) == 0 && graph[i][j] == 1){
						ans += solve(mask - (1<<i), leaf - (1<<i), n - 1, k - 1);
						ans += solve(mask - (1<<i), leaf - (1<<i) + (1<<j), n - 1, k);
				   	}
			   	}
				break;
			}
		}

		return res[mask][leaf] = ans;
	}

    void run(){
		N = nextInt(); M = nextInt(); K = nextInt();
		graph = new int[N][N];

		int x, y;
		for(int i = 0; i < M; i++){
			x = nextInt() - 1; y = nextInt() - 1;
			graph[x][y] = graph[y][x] = 1;
		}

		int[] bitCount = new int[1<<N];
		for(int i = 0; i < bitCount.length; i++){
			bitCount[i] = bitCount[i>>1];
			if(i % 2 == 1) bitCount[i]++;
		}

		long ret = 0;
		res = new long[1<<N][1<<N];
		for(long[] f : res) Arrays.fill(f, -1);
		for(int i = 0; i < (1<<N); i++){
			if(bitCount[i] == K){
				ret += solve((1<<N) - 1, i, N, K);
			}
		}

		System.out.println(ret);
    }

    int nextInt(){
        try{
            int c = System.in.read();
            if(c == -1) return c;
            while(c != '-' && (c < '0' || '9' < c)){
                c = System.in.read();
                if(c == -1) return c;
            }
            if(c == '-') return -nextInt();
            int res = 0;
            do{
                res *= 10;
                res += c - '0';
                c = System.in.read();
            }while('0' <= c && c <= '9');
            return res;
        }catch(Exception e){
            return -1;
        }
    }

    long nextLong(){
        try{
            int c = System.in.read();
            if(c == -1) return -1;
            while(c != '-' && (c < '0' || '9' < c)){
                c = System.in.read();
                if(c == -1) return -1;
            }
            if(c == '-') return -nextLong();
            long res = 0;
            do{
                res *= 10;
                res += c-'0';
                c = System.in.read();
            }while('0' <= c && c <= '9');
            return res;
        }catch(Exception e){
            return -1;
        }
    }

    double nextDouble(){
        return Double.parseDouble(next());
    }

    String next(){
        try{
            StringBuilder res = new StringBuilder("");
            int c = System.in.read();
            while(Character.isWhitespace(c))
                c = System.in.read();
            do{
                res.append((char)c);
            }while(!Character.isWhitespace(c=System.in.read()));
            return res.toString();
        }catch(Exception e){
            return null;
        }
    }

    String nextLine(){
        try{
            StringBuilder res = new StringBuilder("");
            int c = System.in.read();
            while(c == '\r' || c == '\n')
                c = System.in.read();
            do{
                res.append((char)c);
                c = System.in.read();
            }while(c != '\r' && c != '\n');
            return res.toString();
        }catch(Exception e){
            return null;
        }
    }

    public static void main(String[] args){
        new DeadEnds().run();
    }
}


/**
 * Created by IntelliJ IDEA.
 * User: Taras_Brzezinsky
 * Date: 9/13/11
 * Time: 5:34 PM
 * To change this template use File | Settings | File Templates.
 */

import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.io.IOException;
import java.util.Arrays;
import java.util.StringTokenizer;

public class TaskE extends Thread {
    public TaskE() {
        this.input = new BufferedReader(new InputStreamReader(System.in));
        this.output = new PrintWriter(System.out);
        this.setPriority(Thread.MAX_PRIORITY);
    }

    static final long doit(int mask, int dead, int n) {
        if ((mask & dead) == 0) {
            cache[mask][dead] = 0;
            return 0;
        }
        if (cache[mask][dead] != -1) {
            return cache[mask][dead];
        }
        long result = 0;
        for (int a = 0; a < n; ++a) {
            if (((mask & (1 << a)) != 0) && ((dead & (1 << a)) != 0)) {
                for (int b = 0; b < n; ++b) {
                    if (g[a][b] && (mask & (1 << b)) != 0) {
                        if (mask == ((1 << a) | (1 << b))) {
                            cache[mask][dead] = ((dead & mask) == mask) ? 1 : 0;
                            return cache[mask][dead];
                        }
                        if ((dead & (1 << b)) == 0) {
                            result += doit(mask ^ (1 << a), dead, n) + doit(mask ^ (1 << a), dead ^ (1 << b), n);
                        }
                    }
                }
                break;
            }
        }
        cache[mask][dead] = result;
        return result;
    }

    private void solve() throws Throwable {
        int n = nextInt(), m = nextInt(), k = nextInt();
        g = new boolean[n][n];
        cache = new long[1 << n][1 << n];
        for (long[] current : cache) {
            Arrays.fill(current, -1);
        }
        Arrays.fill(cache[0], 1);
        for (int i = 0; i < m; ++i) {
            int a = nextInt() - 1, b = nextInt() - 1;
            g[a][b] = g[b][a] = true;
        }
        long ans = 0;
        for (int dead = 0; dead < (1 << n); ++dead) {
            if (Integer.bitCount(dead) == k) {
                ans += doit((1 << n) - 1, dead, n);
            }
        }
        output.println(ans);

    }

    public void run() {
        try {
            solve();
        } catch (Throwable e) {
            System.err.println(e.getMessage());
            e.printStackTrace();
            System.exit(666);
        } finally {
            output.flush();
            output.close();
        }
    }

    public static void main(String[] args) {
        new TaskE().start();
    }

    private int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }

    private long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }

    private double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }

    private String nextToken() throws IOException {
        while (tokens == null || !tokens.hasMoreTokens()) {
            tokens = new StringTokenizer(input.readLine());
        }
        return tokens.nextToken();
    }

    static long[][] cache;
    static boolean[][] g;
    private BufferedReader input;
    private PrintWriter output;
    private StringTokenizer tokens = null;
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.StringTokenizer;

public class Main {

	/**
	 * @param args
	 */
	static int N, M, K;
	static int[] G, log;
	static long[][] DP;
	public static void main(String[] args) {
		DP = new long[1 << 17][13];

		log = new int[1 << 15];
		for(int i = 0; i < 15; i++)
			log[1 << i] = i;

		InputReader r = new InputReader(System.in);

		N = r.nextInt();
		M = r.nextInt();
		K = r.nextInt();

		G = new int[N];

		int id = 1;
		for(int k = 0; k < M; k++){
			int i = r.nextInt() - 1;
			int j = r.nextInt() - 1;

//			G[Math.min(i, j)] |= 1 << Math.max(i, j);
			G[i] |= 1 << j;
			G[j] |= 1 << i;
		}

		for(long[] i : DP)
			Arrays.fill(i, -1);

		long ret = 0;
		for(int next = G[0]; next > 0; next = (next - 1) & G[0]){
//			System.out.println(Integer.toBinaryString(next));
			ret += go(1, next | 1, Integer.bitCount(next) == 1 ? 1 : 0);
		}

		System.out.println(ret);
	}

	private static long go(int done, int reached, int c) {
		if(done == (1 << N) - 1){
			return c == K ? 1 : 0;
		}else{
			if(DP[gen(done, reached)][c] != -1)return DP[gen(done, reached)][c];

			int can = reached & ~done;
			int curr = can & -can;

//			System.out.println(curr + ", " + currI);
			if(curr == 0)return DP[gen(done, reached)][c] = 0;

			int currI = log[curr];

			long ret = 0;

			ret += go(done | 1 << currI, reached, c + 1);
			for(int next = G[currI] & ~reached; next > 0; next = (next - 1) & G[currI] & ~reached){
//				System.out.println(currI + ", " + next);
				ret += go(done | 1 << currI, reached | next, c);
			}

			return DP[gen(done, reached)][c] = ret;
		}
	}

	private static int gen(int done, int reached) {
		int ret = 0;
		for(int itr = 0; itr < N; itr++){
			ret *= 3;
			if((reached & 1) == 0){
//				if((done & 1) == 1)System.out.println("error");
				ret += 0;
			}else{
				if((done & 1) == 0)ret += 1;
				else ret += 2;
			}

			done /= 2;
			reached /= 2;
		}

		return ret;
	}

	private static String print(int m) {
		String ret = Integer.toBinaryString(m);
		while(ret.length() < N)ret = "0" + ret;
		return ret;
	}

	static class InputReader {
		private BufferedReader reader;
		private StringTokenizer tokenizer;

		public InputReader(InputStream stream) {
			reader = new BufferedReader(new InputStreamReader(stream));
			tokenizer = null;
		}

		public String nextLine() {
			try {
				return reader.readLine();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
				return null;
			}
		}

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(reader.readLine());
				} catch (IOException e) {
					throw new RuntimeException(e);
				}
			}
			return tokenizer.nextToken();
		}

		public int nextInt() {
			return Integer.parseInt(next());
		}

		public long nextLong() {
			return Long.parseLong(next());
		}

		public double nextDouble() {
			return Double.parseDouble(next());
		}
	}
}


import java.io.*;
import java.util.*;

public class E implements Runnable {

	private void solve() throws IOException {
		int n = nextInt();
		int[][] m = new int[n][n];
		int edges = nextInt();
		int k = nextInt();
		for (int i = 0; i < edges; i++) {
			int u = nextInt() - 1, v = nextInt() - 1;
			m[u][v]++;
			m[v][u]++;
		}
		int[][] d = new int[1 << n][1 << n];
		for (int i = 0; i < n; i++) {
			for (int j = 0; j < n; j++) {
				int mask = (1 << i) | (1 << j);
				d[mask][mask] = m[i][j];
			}
		}
		for (int mask = 1; mask < 1 << n; mask++) {
			if (Integer.bitCount(mask) <= 2)
				continue;
			for (int sub = mask; sub > 0; sub = (sub - 1) & mask) {
				int bit = Integer.numberOfTrailingZeros(sub);
				int mask1 = mask ^ (1 << bit);
				int sub1 = sub ^ (1 << bit);
				for (int i = 0; i < n; i++) {
					if ((mask1 & (1 << i)) != 0 && (sub1 & (1 << i)) == 0) {
						d[mask][sub] += m[bit][i] * d[mask1][sub1 | (1 << i)];
						d[mask][sub] += m[bit][i] * d[mask1][sub1];
					}
				}
			}
		}

		int ans = 0;
		for (int mask = 0; mask < 1 << n; mask++) {
			if (Integer.bitCount(mask) == k) {
				ans += d[(1 << n) - 1][mask];
			}
		}
		out.println(ans);
	}

	public static void main(String[] args) {
		new Thread(new E()).start();
	}

	BufferedReader br;
	StringTokenizer st;
	PrintWriter out;
	boolean eof = false;

	public void run() {
		Locale.setDefault(Locale.US);
		try {
			br = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
			out.close();
		} catch (Throwable e) {
			e.printStackTrace();
			System.exit(239);
		}
	}

	String nextToken() {
		while (st == null || !st.hasMoreTokens()) {
			try {
				st = new StringTokenizer(br.readLine());
			} catch (Exception e) {
				eof = true;
				return "0";
			}
		}
		return st.nextToken();
	}

	int nextInt() {
		return Integer.parseInt(nextToken());
	}
}


import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

public class P053E{
	Scanner sc=new Scanner(System.in);

	int INF=1<<28;
	double EPS=1e-9;

	int n, m, k;
	int[] u, v;

	void run(){

		// test();
		n=sc.nextInt();
		m=sc.nextInt();
		k=sc.nextInt();
		// k個が葉になる全域木の個数
		// n<=10
		// m<=50
		u=new int[m];
		v=new int[m];
		for(int i=0; i<m; i++){
			u[i]=sc.nextInt()-1;
			v[i]=sc.nextInt()-1;
		}
		solve();
	}

	void test(){
		n=10;
		m=50;
		m=40;
		k=5;
		u=new int[m];
		v=new int[m];
		for(int i=0; i<m; i++){
			u[i]=(int)(random()*n);
			v[i]=(int)(random()*n);
			for(; v[i]==u[i];){
				v[i]=(int)(random()*n);
			}
			boolean ok=true;
			for(int j=0; j<i; j++){
				ok&=u[i]!=u[j]||v[i]!=v[j];
				ok&=u[i]!=v[j]||v[i]!=u[j];
			}
			if(!ok){
				i--;
				continue;
			}
		}
		solve();
	}

	void solve(){
		long[][] dp=new long[1<<n][1<<n];
		// [s][t]:=sが連結，tが葉，の個数

		for(int i=0; i<n; i++){
			// dp[1<<i][1<<i]=1;
		}
		for(int i=0; i<m; i++){
			dp[(1<<u[i])|(1<<v[i])][(1<<u[i])|(1<<v[i])]=2;
		}
		// dp[1][1]=1;
		for(int s=1; s<1<<n; s++){
			int t=s;
			do{
				if(Integer.bitCount(t)>0){
					dp[s][t]/=Integer.bitCount(t);
				}
				for(int i=0; i<m; i++){
					boolean ub=(s>>u[i]&1)==1;
					boolean vb=(s>>v[i]&1)==1;
					if(ub&!vb){
						dp[s|(1<<v[i])][t&~(1<<u[i])|(1<<v[i])]+=dp[s][t];
					}
					if(!ub&vb){
						dp[s|(1<<u[i])][t&~(1<<v[i])|(1<<u[i])]+=dp[s][t];
					}
				}
				t=(t-1)&s;
			}while(t!=s);
		}
		long ans=0;
		int comb=(1<<k)-1;
		for(; comb<1<<n;){
			ans+=dp[(1<<n)-1][comb];
			int x=comb&-comb, y=comb+x;
			comb=((comb&~y)/x>>>1)|y;
		}
		println(ans+"");
	}

	void println(String s){
		System.out.println(s);
	}

	void print(String s){
		System.out.print(s);
	}

	void debug(Object... os){
		System.err.println(Arrays.deepToString(os));
	}

	public static void main(String[] args){
		Locale.setDefault(Locale.US);
		new P053E().run();
	}
}


import java.util.*;
import java.lang.*;
import java.math.*;
import java.io.*;
import static java.lang.Math.*;
import static java.util.Arrays.*;
import static java.util.Collections.*;

public class P053E{
	Scanner sc=new Scanner(System.in);

	int INF=1<<28;
	double EPS=1e-9;

	int n, m, k;
	int[] u, v;

	void run(){
		n=sc.nextInt();
		m=sc.nextInt();
		k=sc.nextInt();
		u=new int[m];
		v=new int[m];
		for(int i=0; i<m; i++){
			u[i]=sc.nextInt()-1;
			v[i]=sc.nextInt()-1;
		}
		solve();
	}

	void solve(){
		long[][] dp=new long[1<<n][1<<n];
		// dp[s][t]:=「sが連結かつtが葉」の個数

		for(int i=0; i<m; i++){
			dp[(1<<u[i])|(1<<v[i])][(1<<u[i])|(1<<v[i])]=2;
		}
		for(int s=0; s<1<<n; s++){
			int t=s;
			do{
				if(Integer.bitCount(t)>0){
					dp[s][t]/=Integer.bitCount(t);
				}
				for(int i=0; i<m; i++){
					boolean ub=(s>>u[i]&1)==1;
					boolean vb=(s>>v[i]&1)==1;
					if(ub&!vb){
						dp[s|(1<<v[i])][t&~(1<<u[i])|(1<<v[i])]+=dp[s][t];
					}
					if(!ub&vb){
						dp[s|(1<<u[i])][t&~(1<<v[i])|(1<<u[i])]+=dp[s][t];
					}
				}
				t=(t-1)&s;
			}while(t!=s);
		}

		long ans=0;
		int comb=(1<<k)-1;
		for(; comb<1<<n;){
			ans+=dp[(1<<n)-1][comb];
			int x=comb&-comb, y=comb+x;
			comb=((comb&~y)/x>>>1)|y;
		}
		println(ans+"");
	}

	void println(String s){
		System.out.println(s);
	}

	void print(String s){
		System.out.print(s);
	}

	public static void main(String[] args){
		Locale.setDefault(Locale.US);
		new P053E().run();
	}
}


import java.io.*;
import java.math.BigInteger;
import java.util.StringTokenizer;

/**
 * Author: homo_sapiens
 * Date: 7/14/12
 * Time: 11:54 AM
 */
public class Solution {
    public static void main(String[] args) throws IOException {
        Solution solution = new Solution();
        solution.run();
    }

    private int n;
    private int[] a;
    private BigInteger[][][] z;

    private void run() throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(System.out));

        String s = in.readLine();

        a = new int[s.length()];
        for (int i = 0; i < s.length(); i++) {
            a[i] = s.charAt(i) == 'A' ? 0 : 1;
        }

        z = new BigInteger[s.length() + 1][4][4];

        for (int i = 0; i <= s.length(); i++) {
            for (int j = 0; j < 4; j++) {
                for (int k = 0; k < 4; k++) {
                    z[i][j][k] = BigInteger.valueOf(-1);
                }
            }
        }

        BigInteger result = BigInteger.ZERO;

        for (int mask = 0; mask < 4; mask++) {
            result = result.add(solve(2, mask, mask));
        }

        out.write(result.toString());
        out.newLine();

        out.close();
        in.close();
    }

    private BigInteger solve(int idx, int mask1, int mask2) {
        if (!z[idx][mask1][mask2].equals(BigInteger.valueOf(-1))) {
            return z[idx][mask1][mask2];
        }

        int f1 = mask1 & 1, f2 = (mask1 >> 1) & 1;
        int s1 = mask2 & 1, s2 = (mask2 >> 1) & 1;

        BigInteger result = BigInteger.ZERO;

        if (idx == a.length) {
            if (correct(s1, s2, f1, a[idx - 2], a[idx - 1], a[0])
                    && correct(s2, f1, f2, a[idx - 1], a[0], a[1])) {
                result = BigInteger.ONE;
            }
        } else {
            for (int cur = 0; cur < 2; cur++) {
                if (correct(s1, s2, cur, a[idx - 2], a[idx - 1], a[idx])) {
                    result = result.add(solve(idx + 1, mask1, (cur << 1) | s2));
                }
            }
        }

        return z[idx][mask1][mask2] = result;
    }

    private boolean correct(int a1, int a2, int a3, int b1, int b2, int b3) {
        if (a1 == 0 && a2 == 1) {
            return b1 == 1 && b2 == 0;
        } else if (a2 == 0 && a3 == 1) {
            return b2 == 1 && b3 == 0;
        } else {
            return a2 == b2;
        }
    }
}


import java.util.*;
import java.io.*;
import java.math.*;

public class Main {
    public static void main(String[] args) {
        Scanner cin = new Scanner(System.in);
        int N = cin.nextInt();
        int K = cin.nextInt();
        long ans = (new Solver(N, K)).solve();
        System.out.println(ans);
    }
}

class Solver {
    int N, K;
    long[][][] big, small;
    static long[][] comb;
    static final int Mod = 1000000000 + 7;
    static {
        comb = new long[13][13];
        for (int i = 0; i <= 12; ++i) {
            for (int j = 0; j <= i; ++j) {
                if (j == 0 || j == i) {
                    comb[i][j] = 1;
                }
                else {
                    comb[i][j] = (comb[i - 1][j - 1] + comb[i - 1][j]) % Mod;
                }
            }
        }
    }
    Solver(int N, int K) {
        this.N = N;
        this.K = K;
        big = new long[N + 1][K + 1][1 << 4];
        small = new long[N + 1][K + 1][1 << 4];
        for (int i = 0; i <= N; ++i) {
            for (int j = 0; j <= K; ++j) {
                for (int k = 0; k < 16; ++k) {
                    big[i][j][k] = small[i][j][k] = -1;
                }
            }
        }
    }
    long solve() {
        long res = calcBig(N, K, 15);
        for (int i = K; i >= 1; --i) {
            res = res * i % Mod;
        }
        return res;
    }
    long calcBig(int size, int count, int mask) {
        if (count < 0) {
            return 0;
        }
        if (big[size][count][mask] != -1) {
            return big[size][count][mask];
        }
        long res = 0;
        if (mask == 15) {
            res += 2 * calcBig(0, count - 2, 0);
        }
        for (int i = 0; i < 4; ++i) {
            int j = (i + 1) & 3;
            if ((mask >> i & 1) == 1 && (mask >> j & 1) == 1) {
                int nxt = mask ^ (1 << i) ^ (1 << j);
                for (int k = nxt; ; k = (k - 1) & nxt) {
                    res += calcSmall(size, count - 1 - Integer.bitCount(k), nxt - k);
                    if (k == 0) {
                        break;
                    }
                }
            }
        }
        int nxt = mask;
        for (int k = nxt; ; k = (k - 1) & nxt) {
            res += calcSmall(size, count - Integer.bitCount(k), nxt - k);
            if (k == 0) {
                break;
            }
        }
        return big[size][count][mask] = res % Mod;
    }
    long calcSmall(int size, int count, int mask) {
        if (count < 0) {
            return 0;
        }
        if (small[size][count][mask] != -1) {
            return small[size][count][mask];
        }
        if (size == 0) {
            return count == 0 ? 1 : 0;
        }
        long res = 0;
        int maxCount = Integer.bitCount(mask) * 3;
        int pairCount = 0;
        for (int i = 0; i < 4; ++i) {
            int j = (i + 1) & 3;
            if ((mask >> i & 1) == 1 && (mask >> j & 1) == 1) {
                pairCount++;
            }
        }
        for (int i = 0; i <= pairCount; ++i) {
            for (int j = 0; j <= maxCount - i * 2; ++j) {
                res += calcBig(size - 1, count - i - j, mask) * comb[pairCount][i] % Mod * comb[maxCount - i * 2][j] % Mod;
            }
        }
        return small[size][count][mask] = res % Mod;
    }
}


import java.io.OutputStreamWriter;
import java.io.BufferedWriter;
import java.util.Comparator;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.List;
import java.io.IOException;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.ArrayList;
import java.util.NoSuchElementException;
import java.math.BigInteger;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 * @author Egor Kulikov (egor@egork.net)
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		InputReader in = new InputReader(inputStream);
		OutputWriter out = new OutputWriter(outputStream);
		TaskE solver = new TaskE();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskE {
	static final long MOD = 1000000007;

	long[][][] result;
	long[][][] resultSmall;
	long[][] c = IntegerUtils.generateBinomialCoefficients(13);

    public void solve(int testNumber, InputReader in, OutputWriter out) {
		int size = in.readInt();
		int count = in.readInt();
		result = new long[size + 1][count + 1][16];
		resultSmall = new long[size + 1][count + 1][16];
		ArrayUtils.fill(result, -1);
		ArrayUtils.fill(resultSmall, -1);
		long answer = calculate(size, count, 0);
		answer *= IntegerUtils.factorial(count, MOD);
		answer %= MOD;
		out.printLine(answer);
    }

	private long calculate(int size, int count, int mask) {
		if (count < 0)
			return 0;
		if (result[size][count][mask] != -1)
			return result[size][count][mask];
		long current = 0;
		if (mask == 0)
			current += 2 * calculate(0, count - 2, 15);
		for (int i = 0; i < 4; i++) {
			int j = (i + 1) & 3;
			if ((mask >> i & 1) != 0 || (mask >> j & 1) != 0)
				continue;
			int remaining = 15 - mask - (1 << i) - (1 << j);
			for (int k = remaining; ; k = (k - 1) & remaining) {
				current += calculateSmall(size, count - 1 - Integer.bitCount(k), mask + (1 << i) + (1 << j) + k);
				if (k == 0)
					break;
			}
		}
		int remaining = 15 - mask;
		for (int k = remaining; ; k = (k - 1) & remaining) {
			current += calculateSmall(size, count - Integer.bitCount(k), mask + k);
			if (k == 0)
				break;
		}
		return result[size][count][mask] = current % MOD;
	}

	private long calculateSmall(int size, int count, int mask) {
		if (count < 0)
			return 0;
		if (resultSmall[size][count][mask] != -1)
			return resultSmall[size][count][mask];
		if (size == 0)
			return resultSmall[size][count][mask] = count == 0 ? 1 : 0;
		int max = 3 * Integer.bitCount(15 - mask);
		int pairCount = 0;
		for (int i = 0; i < 4; i++) {
			int j = (i + 1) & 3;
			if ((mask >> i & 1) == 0 && ((mask >> j & 1) == 0))
				pairCount++;
		}
		long current = 0;
		for (int j = 0; j <= pairCount; j++) {
			for (int i = 0; i <= max - 2 * j; i++)
				current += calculate(size - 1, count - i - j, mask) * c[max - 2 * j][i] * c[pairCount][j];
		}
		return resultSmall[size][count][mask] = current % MOD;
	}
}

class IntegerUtils {

    public static long[][] generateBinomialCoefficients(int n) {
		long[][] result = new long[n + 1][n + 1];
		for (int i = 0; i <= n; i++) {
			result[i][0] = 1;
			for (int j = 1; j <= i; j++)
				result[i][j] = result[i - 1][j - 1] + result[i - 1][j];
		}
		return result;
	}

	public static long factorial(int n, long mod) {
		long result = 1;
		for (int i = 2; i <= n; i++)
			result = result * i % mod;
		return result % mod;
	}

	}

class InputReader {

	private InputStream stream;
	private byte[] buf = new byte[1024];
	private int curChar;
	private int numChars;
	private SpaceCharFilter filter;

	public InputReader(InputStream stream) {
		this.stream = stream;
	}

	public int read() {
		if (numChars == -1)
			throw new InputMismatchException();
		if (curChar >= numChars) {
			curChar = 0;
			try {
				numChars = stream.read(buf);
			} catch (IOException e) {
				throw new InputMismatchException();
			}
			if (numChars <= 0)
				return -1;
		}
		return buf[curChar++];
	}

	public int readInt() {
		int c = read();
		while (isSpaceChar(c))
			c = read();
		int sgn = 1;
		if (c == '-') {
			sgn = -1;
			c = read();
		}
		int res = 0;
		do {
			if (c < '0' || c > '9')
				throw new InputMismatchException();
			res *= 10;
			res += c - '0';
			c = read();
		} while (!isSpaceChar(c));
		return res * sgn;
	}

	public boolean isSpaceChar(int c) {
		if (filter != null)
			return filter.isSpaceChar(c);
		return isWhitespace(c);
	}

	public static boolean isWhitespace(int c) {
		return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
	}

	public interface SpaceCharFilter {
		public boolean isSpaceChar(int ch);
	}
}

class OutputWriter {
	private final PrintWriter writer;

	public OutputWriter(OutputStream outputStream) {
		writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
	}

	public OutputWriter(Writer writer) {
		this.writer = new PrintWriter(writer);
	}

	public void print(Object...objects) {
		for (int i = 0; i < objects.length; i++) {
			if (i != 0)
				writer.print(' ');
			writer.print(objects[i]);
		}
	}

    public void printLine(Object...objects) {
		print(objects);
		writer.println();
	}

	public void close() {
		writer.close();
	}

	}

class ArrayUtils {

	public static void fill(long[][] array, long value) {
		for (long[] row : array)
			Arrays.fill(row, value);
	}

	public static void fill(long[][][] array, long value) {
		for (long[][] row : array)
			fill(row, value);
	}

	}