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

public class E {

	static int[] tree;

	static void fill(int idx) {
		if (idx >= tree.length) return;
		fill(2 * idx);
		fill(2 * idx + 1);
		tree[idx] = 1;
		if (2 * idx < tree.length) tree[idx] += tree[2 * idx];
		if (2 * idx + 1 < tree.length) tree[idx] += tree[2 * idx + 1];
	}

	static boolean shouldAdd(int idx) {
		if (idx % 2 == 1) return true;
		while (idx % 2 == 0) {
			idx /= 2;
		}
		return tree[2 * idx] % 2 == 0;
	}

	static void add(int idx) {
		while (idx >= 1) {
			tree[idx]++;
			idx /= 2;
		}
	}

	public static void main(String[] args) throws IOException {
		MyScanner sc = new MyScanner();
		PrintWriter out = new PrintWriter(System.out);
		int N = sc.nextInt();
		int level = 0, got = 1;
		while (N >= got) {
			N -= got;
			level++;
			got *= 2;
		}
		tree = new int[1 << level];
		fill(1);
		for (int i = tree.length - 1; i > 1 << (level-1); i--) {
			if (shouldAdd(i)) {
				add(i);
				N--;
			}
		}

		out.println(N == 0 || N == 1 ? 1 : 0);

		out.flush();
	}

	static class MyScanner {
		private BufferedReader br;
		private StringTokenizer tokenizer;

		public MyScanner() {
			br = new BufferedReader(new InputStreamReader(System.in));
		}

		public String next() {
			while (tokenizer == null || !tokenizer.hasMoreTokens()) {
				try {
					tokenizer = new StringTokenizer(br.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());
		}
	}
}


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

public class Main implements Runnable {
  final boolean isFileIO = false;
  BufferedReader in;
  PrintWriter out;
  StringTokenizer st = new StringTokenizer("");
  String delim = " ";

  public static void main(String[] args) {
    new Thread(null, new Main(), "", 268435456).start();
  }

  public void run() {
    try {
      initIO();
      solve();
      out.close();
    } catch(Exception e) {
      e.printStackTrace(System.err);
      System.exit(-1);
    }
  }

  public void initIO() throws IOException {
    if(!isFileIO) {
      in = new BufferedReader(new InputStreamReader(System.in));
      out = new PrintWriter(System.out);
    } else {
      in = new BufferedReader(new FileReader("input.txt"));
      out = new PrintWriter("output.txt");
    }
  }

  String nextToken() throws IOException {
    if(!st.hasMoreTokens()) {
      st = new StringTokenizer(in.readLine());
    }
    return st.nextToken(delim);
  }

  String readLine() throws IOException {
    return in.readLine();
  }

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

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

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

  void solve() throws IOException {
    int[] a = new int[4];
    int[] b = new int[4];
    for(int i = 0; i < 4; i++) {
      a[i] = nextInt(); b[i] =nextInt();
    }

    boolean isWin = true;
    for(int i = 0; i < 2; i++) {
      isWin = true;
      for(int j = 0; j < 2; j++) {
        if(!(a[i] > b[j + 2] && b[1 - i] > a[3 - j]))
          isWin = false;
      }
      if(isWin) {
        out.println("Team 1");
        return;
      }
    }
    for(int i = 0; i < 2; i++) {
      isWin = false;
      for(int j = 0; j < 2; j++) {
        if(b[i] < a[j + 2] && a[1 - i] < b[3 - j]) {
          isWin = true;
          break;
        }
      }
      if(!isWin) {
        out.println("Draw");
        return;
      }
    }
    if(isWin) {
      out.println("Team 2");
      return;
    }
  }
}


import java.util.*;
public class Main {
    public static void main(String[] args) {
        Scanner sc=new Scanner(System.in);

        //System.out.println(qmod(2,5,100));

        long S[][]=new long[5005][5005];
        long mod=998244353;
        S[1][1]=1;
        S[0][0]=0;
        for(int i=1;i<=5000;i++){
            S[i][i]=1;S[i][0]=0;
        }
        for(int i=2;i<=5000;i++){
            for(int j=1;j<=i;j++){
                S[i][j]=(S[i-1][j]*j%mod+S[i-1][j-1])%mod;
            }
        }
        long n=sc.nextLong();long m=sc.nextLong();int k=sc.nextInt();
        m=qmod(m,mod-2,mod);
        long dp[]=new long[5005];dp[0]=1;
        for(int i=1;i<=Math.min(n,k);i++)dp[i]=dp[i-1]*(n-i+1)%mod;

        long ans=0;
        for(int i=1;i<=Math.min(n,k);i++){
            ans=(ans+dp[i]*qmod(m,i,mod)%mod*S[k][i]%mod)%mod;
        }
        System.out.println(ans);

    }
    public static long qmod(long a,long b,long mod){
        long ans=1;
        while(b>=1){

            if((b&1)!=0){
                ans=ans*a%mod;
            }
            a=a*a%mod;
            b=b>>1;
        }return ans;
    }
}


import java.io.IOException;
import java.io.InputStreamReader;
import java.util.InputMismatchException;
import java.util.ArrayList;
import java.io.BufferedReader;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.Writer;
import java.util.StringTokenizer;
import java.io.InputStream;

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

class TaskD {
    public void solve(int testNumber, Reader in, OutputWriter out) {
        long n = in.nextLong();
        ArrayList<Integer> lengths = new ArrayList<Integer>();
        long ones = n;
        boolean[] used = new boolean[101010];
        for(int i = 2; i * i <= n; ++i){
            if (used[i])
                continue;
            long j = i;
            int len = 0;
            while(j <= n) {
                if(j < 101010)
                    used[(int)j] = true;
                ++len;
                j *= i;
            }

            lengths.add(len);
            ones -= len;
        }

        long gandy = 0;

        if(ones % 2 != 0)
            gandy ^= gandy(1);
        long[] dp = new long[30];
        for(int i = 0; i < 30; ++i) {
            dp[i] = gandy(i);
        }
        for (Integer length : lengths) {
            gandy ^= dp[length];
        }

        out.println(gandy == 0 ? "Petya" : "Vasya");
    }

    private long gandy(int length) {
        if (length == 0) return 0;
        if (length == 1) return 1;
        if (length == 2) return 2;
        if (length == 3) return 1;
        if (length == 4) return 4;
        if (length == 5) return 3;
        if (length == 6) return 2;
        if (length == 7) return 1;
        if (length == 8) return 5;
        if (length == 9) return 6;
        if (length == 10) return 2;
        if (length == 11) return 1;
        if (length == 12) return 8;
        if (length == 13) return 7;
        if (length == 14) return 5;
        if (length == 15) return 9;
        if (length == 16) return 8;
        if (length == 17) return 7;
        if (length == 18) return 3;
        if (length == 19) return 4;
        if (length == 20) return 7;
        if (length == 21) return 4;
        if (length == 22) return 2;
        if (length == 23) return 1;
        if (length == 24) return 10;
        if (length == 25) return 9;
        if (length == 26) return 3;
        if (length == 27) return 6;
        if (length == 28) return 11;
        if (length == 29) return 12;
        throw new AssertionError();
    }
}

class Reader {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

    public Reader(BufferedReader reader) {
        this.reader = reader;
    }

    public Reader(InputStream stream) {
        this(new BufferedReader(new InputStreamReader(stream)));
    }

    public String nextString() {
        while (tokenizer == null || !tokenizer.hasMoreTokens()) {
            tokenizer = new StringTokenizer(readLine());
        }
        return tokenizer.nextToken();
    }

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

    private String readLine() {
        try {
            return reader.readLine();
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

class OutputWriter extends PrintWriter {

	public OutputWriter(OutputStream out) {
		super(out);
	}

	public OutputWriter(java.io.Writer writer){
		super(writer);
	}

	}


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

public class A {
    FastScanner in;
    PrintWriter out;

    int gcd(int x, int y) {
        return x == 0 ? y : gcd(y % x, x);
    }

    int getCost(int n, boolean[] already) {
        boolean[] z = new boolean[n];
        for (int x = 3; x < n; x++) {
            if (!already[x]) {
                continue;
            }
            int g = gcd(n, x);
            int add = n / g;
            for (int i = 0; i < n; i += add) {
                z[i] = true;
            }
        }
        int cost = 0;
        for (int i = 0; i < n; i++) {
            cost += z[i] ? 0 : 1;
        }
        return cost;
    }

    int getAns(int maxN, int k) {
        int res = 0;
        boolean[] already = new boolean[maxN + 1];
        int[] costA = new int[maxN + 1];
        for (int it = 0; it < k; it++) {
            int mincost = Integer.MAX_VALUE;
            int minVal = -1;
            for (int n = 3; n <= maxN; n++) {
                if (already[n]) {
                    continue;
                }
                int cost = getCost(n, already);
                if (cost < mincost) {
                    mincost = cost;
                    minVal = n;
                }
            }
            already[minVal] = true;
            res += mincost;
//            System.err.println("! " + minVal + " " + mincost);
            costA[minVal] = mincost;
        }
//        System.err.println(Arrays.toString(costA));
        return res;
    }

    void solve() {
        int n = in.nextInt();
        int k = in.nextInt();
        out.println(solve(n, k));
    }

    void solvesd() {
        for (int n = 10; n <= 15; n++) {
            System.err.println("n = " + n);
            for (int k = 1; k + 2 <= n; k++) {
                long correct = getAns(n, k);
                long my = solve(n, k);
                if (correct != my) {
                    throw new AssertionError(n + " " + k + " " + correct + " " + my);
                }
            }
        }
    }

    long solve(int maxN, int k) {
        final int MAX = (int) 1e6 + 10;
        int[] prime = new int[MAX];
        Arrays.fill(prime, -1);
        for (int i = 2; i < MAX; i++) {
            if (prime[i] == -1) {
                for (int j = i; j < MAX; j += i) {
                    prime[j] = i;
                }
            }
        }
        int[] phi = new int[MAX];
        for (int i = 2; i < MAX; i++) {
            int n = i;
            int result = n;
            while (n != 1) {
                int pr = prime[n];
                while (n % pr == 0) {
                    n /= pr;
                }
                result -= result / pr;
            }
            phi[i] = result;
        }
        long cost = 1;
        if (k >= 2) {
            cost++;
        }
        List<Integer>[] where = new ArrayList[MAX + 1];
        for (int i = 0; i < where.length; i++) {
            where[i] = new ArrayList<>();
        }
//        System.err.println("NEED " + k);
        for (int i = 3; i <= maxN; i++) {
            where[phi[i]].add(i);
//            System.err.println("!" + phi[i]);
        }
        for (int c = 2; k != 0; c++) {
            int sz = where[c].size();
            int use = Math.min(k, sz);
            k -= use;
            cost += c * 1L * use;
        }
        return cost;
    }

    void solve22() {
//        for (int n = 3; n <= 40; n++) {
//            for (int k = 1; k <= n - 3; k++) {
//                System.err.print(getAns(n, k) + " ");
//            }
//            System.err.println();
//        }
        getAns(60, 50);
//        out.println(getAns(in.nextInt(), in.nextInt()));
    }

    void solve123() {
        for (int n = 3; n <= 50; n++) {
            boolean[] z = new boolean[n];
            for (int x = 3; x < n; x++) {
                int g = gcd(n, x);
                int add = n / g;
                for (int i = 0; i < n; i += add) {
                    z[i] = true;
                }
            }
            int cost = 0;
            for (int i = 0; i < n; i++) {
                cost += z[i] ? 0 : 1;
            }
            System.err.println(n + " -> " + cost);
        }
    }

    void run() {
        try {
            in = new FastScanner(new File("A.in"));
            out = new PrintWriter(new File("A.out"));

            solve();

            out.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }

    void runIO() {

        in = new FastScanner(System.in);
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(File f) {
            try {
                br = new BufferedReader(new FileReader(f));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }

        public FastScanner(InputStream f) {
            br = new BufferedReader(new InputStreamReader(f));
        }

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

        boolean hasMoreTokens() {
            while (st == null || !st.hasMoreTokens()) {
                String s = null;
                try {
                    s = br.readLine();
                } catch (IOException e) {
                    e.printStackTrace();
                }
                if (s == null)
                    return false;
                st = new StringTokenizer(s);
            }
            return true;
        }

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

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

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

    public static void main(String[] args) {
        new A().runIO();
    }
}


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

public class Problems {

    public static void main(String[] args) throws IOException {

        new Problems().runMain();
    }

    void runMain() {
		Scanner sc = new Scanner(System.in);

        int n = sc.nextInt();
        int a[] = new int[n];
        int b[] = new int[n];
        float max = 0;
        for (int i = 0; i < n; i++) {
        	a[i] = sc.nextInt();
        	if (i > 0) {
        		max = lcm(a[i], (long)max);
        	} else {
        		max = a[0];
        	}
        }
        for (int i = 0; i < n; i++) {
        	b[i] = sc.nextInt();
        }

        float counter = 0;
        for (int i = 0; i < max; i++) {
        	for (int j = 0; j < n; j++) {
        		if (i % a[j] == b[j]) {
        			counter++;
        			break;
        		}
        	}
        }
        System.out.printf("%.5f", counter/max);
    }

    long gcd(long a, long b){
    	return b == 0 ? a : gcd(b,a % b);
    }

    long lcm(long a, long b){
    	return a / gcd(a,b) * b;
    }
}


import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.AbstractMap;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import java.util.Set;
import java.util.SortedMap;
import java.util.SortedSet;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.function.BiConsumer;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Supplier;
import java.util.stream.Stream;

public class E_418
{
	public static final long[] POWER2 = generatePOWER2();
	public static final BigInteger[] FACULTY_BIG = generateFacultyBig();
	public static final BigInteger TWO = BigInteger.valueOf(2);
	public static final long BIG = 1000000007;
	public static final IteratorBuffer<Long> ITERATOR_BUFFER_PRIME = new IteratorBuffer<>(streamPrime(1000000).iterator());
	private static BufferedReader bufferedReader = new BufferedReader(new InputStreamReader(System.in));
	private static StringTokenizer stringTokenizer = null;
	private static PrintWriter out = new PrintWriter(new BufferedOutputStream(System.out));

	interface BiFunctionResult<Type0, Type1, TypeResult>
	{
		TypeResult apply(Type0 x0, Type1 x1, TypeResult x2);
	}

	static class Array<Type> implements Iterable<Type>
	{
		private Object[] array;

		public Array(int size)
		{
			this.array = new Object[size];
		}

		public Array(int size, Type element)
		{
			this(size);
			Arrays.fill(this.array, element);
		}

		public Array(Array<Type> array, Type element)
		{
			this(array.size() + 1);
			for (int index = 0; index < array.size(); index++)
			{
				set(index, array.get(index));
			}
			set(size() - 1, element);
		}

		public Array(List<Type> list)
		{
			this(list.size());
			int index = 0;
			for (Type element : list)
			{
				set(index, element);
				index += 1;
			}
		}

		public Type get(int index)
		{
			return (Type) this.array[index];
		}

		public Array set(int index, Type value)
		{
			this.array[index] = value;
			return this;
		}

		public int size()
		{
			return this.array.length;
		}

		public List<Type> toList()
		{
			List<Type> result = new ArrayList<>();
			for (Type element : this)
			{
				result.add(element);
			}
			return result;
		}

		@Override
		public Iterator<Type> iterator()
		{
			return new Iterator<Type>()
			{
				int index = 0;

				@Override
				public boolean hasNext()
				{
					return this.index < size();
				}

				@Override
				public Type next()
				{
					Type result = Array.this.get(index);
					index += 1;
					return result;
				}
			};
		}

		@Override
		public String toString()
		{
			return "[" + E_418.toString(this, ", ") + "]";
		}
	}

	static abstract class Edge<TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>>
	{
		public final TypeVertex vertex0;
		public final TypeVertex vertex1;
		public final boolean bidirectional;

		public Edge(TypeVertex vertex0, TypeVertex vertex1, boolean bidirectional)
		{
			this.vertex0 = vertex0;
			this.vertex1 = vertex1;
			this.bidirectional = bidirectional;
			this.vertex0.edges.add(getThis());
			if (this.bidirectional)
			{
				this.vertex1.edges.add(getThis());
			}
		}

		public TypeVertex other(Vertex<TypeVertex, TypeEdge> vertex)
		{
			TypeVertex result;
			if (vertex0 == vertex)
			{
				result = vertex1;
			}
			else
			{
				result = vertex0;
			}
			return result;
		}

		public abstract TypeEdge getThis();

		public void remove()
		{
			this.vertex0.edges.remove(getThis());
			if (this.bidirectional)
			{
				this.vertex1.edges.remove(getThis());
			}
		}

		@Override
		public String toString()
		{
			return this.vertex0 + "->" + this.vertex1;
		}
	}

	public static class EdgeDefault<TypeVertex extends Vertex<TypeVertex, EdgeDefault<TypeVertex>>> extends Edge<TypeVertex, EdgeDefault<TypeVertex>>
	{
		public EdgeDefault(TypeVertex vertex0, TypeVertex vertex1, boolean bidirectional)
		{
			super(vertex0, vertex1, bidirectional);
		}

		@Override
		public EdgeDefault<TypeVertex> getThis()
		{
			return this;
		}
	}

	public static class Vertex<TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>> implements Comparable<Vertex<? super TypeVertex, ? super TypeEdge>>
	{
		public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>> void depthFirstSearch(
				Array<TypeVertex> vertices,
				int indexVertexStart,
				BiConsumer<TypeVertex, TypeEdge> functionPreVisit,
				BiConsumer<TypeVertex, TypeEdge> functionInVisit,
				BiConsumer<TypeVertex, TypeEdge> functionPostVisit
		)
		{
			TypeVertex vertexTo;
			TypeEdge edgeTo;
			boolean[] isOnStack = new boolean[vertices.size()];
			Stack<Operation> stackOperations = new Stack<>();
			Stack<TypeVertex> stackVertices = new Stack<>();
			Stack<TypeEdge> stackEdges = new Stack<>();

			TypeVertex vertexStart = vertices.get(indexVertexStart);
			stackOperations.push(Operation.EXPAND);
			stackVertices.push(vertexStart);
			stackEdges.push(null);
			isOnStack[vertexStart.index] = true;
			while (!stackOperations.isEmpty())
			{
				Operation operation = stackOperations.pop();
				TypeVertex vertex = stackVertices.pop();
				TypeEdge edge = stackEdges.pop();
				switch (operation)
				{
					case INVISIT:
						functionInVisit.accept(vertex, edge);
						break;
					case POSTVISIT:
						functionPostVisit.accept(vertex, edge);
						break;
					case EXPAND:
						stackOperations.push(Operation.POSTVISIT);
						stackVertices.push(vertex);
						stackEdges.push(edge);
						Integer indexTo = null;
						for (int index = 0; indexTo == null && index < vertex.edges.size(); index++)
						{
							edgeTo = vertex.edges.get(index);
							vertexTo = edgeTo.other(vertex);
							if (!isOnStack[vertexTo.index])
							{
								indexTo = index;
							}
						}
						if (indexTo != null)
						{
							edgeTo = vertex.edges.get(indexTo);
							vertexTo = edgeTo.other(vertex);
							stackOperations.push(Operation.EXPAND);
							stackVertices.push(vertexTo);
							stackEdges.push(edgeTo);
							isOnStack[vertexTo.index] = true;
							for (int index = indexTo + 1; index < vertex.edges.size(); index++)
							{
								edgeTo = vertex.edges.get(index);
								vertexTo = edgeTo.other(vertex);
								if (!isOnStack[vertexTo.index])
								{
									stackOperations.push(Operation.INVISIT);
									stackVertices.push(vertex);
									stackEdges.push(edge);
									stackOperations.push(Operation.EXPAND);
									stackVertices.push(vertexTo);
									stackEdges.push(edgeTo);
									isOnStack[vertexTo.index] = true;
								}
							}
						}
						functionPreVisit.accept(vertex, edge);
						break;
				}
			}
		}

		public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>> void depthFirstSearch(
				Array<TypeVertex> vertices,
				int indexVertexStart,
				Consumer<TypeVertex> functionPreVisit,
				Consumer<TypeVertex> functionInVisit,
				Consumer<TypeVertex> functionPostVisit
		)
		{
			depthFirstSearch(
					vertices,
					indexVertexStart,
					(vertex, edge) -> functionPreVisit.accept(vertex),
					(vertex, edge) -> functionInVisit.accept(vertex),
					(vertex, edge) -> functionPostVisit.accept(vertex)
			);
		}

		public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>, TypeResult> TypeResult breadthFirstSearch(
				TypeVertex vertex,
				TypeEdge edge,
				BiFunctionResult<TypeVertex, TypeEdge, TypeResult> function,
				Array<Boolean> visited,
				FIFO<TypeVertex> verticesNext,
				FIFO<TypeEdge> edgesNext,
				TypeResult result
		)
		{
			if (!visited.get(vertex.index))
			{
				visited.set(vertex.index, true);
				result = function.apply(vertex, edge, result);
				for (TypeEdge edgeNext : vertex.edges)
				{
					TypeVertex vertexNext = edgeNext.other(vertex);
					if (!visited.get(vertexNext.index))
					{
						verticesNext.push(vertexNext);
						edgesNext.push(edgeNext);
					}
				}
			}
			return result;
		}

		public static <TypeVertex extends Vertex<TypeVertex, TypeEdge>, TypeEdge extends Edge<TypeVertex, TypeEdge>, TypeResult> TypeResult breadthFirstSearch(
				Array<TypeVertex> vertices,
				int indexVertexStart,
				BiFunctionResult<TypeVertex, TypeEdge, TypeResult> function,
				TypeResult result
		)
		{
			Array<Boolean> visited = new Array<>(vertices.size(), false);
			FIFO<TypeVertex> verticesNext = new FIFO<>();
			verticesNext.push(vertices.get(indexVertexStart));
			FIFO<TypeEdge> edgesNext = new FIFO<>();
			edgesNext.push(null);
			while (!verticesNext.isEmpty())
			{
				result = breadthFirstSearch(verticesNext.pop(), edgesNext.pop(), function, visited, verticesNext, edgesNext, result);
			}
			return result;
		}

		public final int index;
		public final List<TypeEdge> edges;

		public Vertex(int index)
		{
			this.index = index;
			this.edges = new ArrayList<>();
		}

		@Override
		public int compareTo(Vertex<? super TypeVertex, ? super TypeEdge> that)
		{
			return Integer.compare(this.index, that.index);
		}

		@Override
		public String toString()
		{
			return "" + this.index;
		}

		enum Operation
		{
			INVISIT, POSTVISIT, EXPAND
		}
	}

	public static class VertexDefault<TypeEdge extends Edge<VertexDefault<TypeEdge>, TypeEdge>> extends Vertex<VertexDefault<TypeEdge>, TypeEdge>
	{
		public VertexDefault(int index)
		{
			super(index);
		}
	}

	public static class VertexDefaultDefault extends Vertex<VertexDefaultDefault, EdgeDefaultDefault>
	{
		public static Array<VertexDefaultDefault> vertices(int n)
		{
			Array<VertexDefaultDefault> result = new Array<>(n);
			for (int index = 0; index < n; index++)
			{
				result.set(index, new VertexDefaultDefault(index));
			}
			return result;
		}

		public VertexDefaultDefault(int index)
		{
			super(index);
		}
	}

	public static class EdgeDefaultDefault extends Edge<VertexDefaultDefault, EdgeDefaultDefault>
	{
		public EdgeDefaultDefault(VertexDefaultDefault vertex0, VertexDefaultDefault vertex1, boolean bidirectional)
		{
			super(vertex0, vertex1, bidirectional);
		}

		@Override
		public EdgeDefaultDefault getThis()
		{
			return this;
		}
	}

	public static class Tuple2<Type0, Type1>
	{
		public final Type0 v0;
		public final Type1 v1;

		public Tuple2(Type0 v0, Type1 v1)
		{
			this.v0 = v0;
			this.v1 = v1;
		}

		@Override
		public String toString()
		{
			return "(" + this.v0 + ", " + this.v1 + ")";
		}
	}

	static class Wrapper<Type>
	{
		public Type value;

		public Wrapper(Type value)
		{
			this.value = value;
		}

		public Type get()
		{
			return this.value;
		}

		public void set(Type value)
		{
			this.value = value;
		}

		@Override
		public String toString()
		{
			return this.value.toString();
		}
	}

	public static class Tuple3<Type0, Type1, Type2>
	{
		public final Type0 v0;
		public final Type1 v1;
		public final Type2 v2;

		public Tuple3(Type0 v0, Type1 v1, Type2 v2)
		{
			this.v0 = v0;
			this.v1 = v1;
			this.v2 = v2;
		}

		@Override
		public String toString()
		{
			return "(" + this.v0 + ", " + this.v1 + ", " + this.v2 + ")";
		}
	}

	public static class Tuple2Comparable<Type0 extends Comparable<? super Type0>, Type1 extends Comparable<? super Type1>> extends Tuple2<Type0, Type1> implements Comparable<Tuple2Comparable<Type0, Type1>>
	{
		public Tuple2Comparable(Type0 v0, Type1 v1)
		{
			super(v0, v1);
		}

		@Override
		public int compareTo(Tuple2Comparable<Type0, Type1> that)
		{
			int result = this.v0.compareTo(that.v0);
			if (result == 0)
			{
				result = this.v1.compareTo(that.v1);
			}
			return result;
		}
	}

	public static class SingleLinkedList<Type>
	{
		public final Type element;
		public SingleLinkedList<Type> next;

		public SingleLinkedList(Type element, SingleLinkedList<Type> next)
		{
			this.element = element;
			this.next = next;
		}

		public void toCollection(Collection<Type> collection)
		{
			if (this.next != null)
			{
				this.next.toCollection(collection);
			}
			collection.add(this.element);
		}
	}

	public static class Node<Type>
	{
		public static <Type> Node<Type> balance(Node<Type> result)
		{
			while (result != null && 1 < Math.abs(height(result.left) - height(result.right)))
			{
				if (height(result.left) < height(result.right))
				{
					Node<Type> right = result.right;
					if (height(right.right) < height(right.left))
					{
						result = new Node<>(result.value, result.left, right.rotateRight());
					}
					result = result.rotateLeft();
				}
				else
				{
					Node<Type> left = result.left;
					if (height(left.left) < height(left.right))
					{
						result = new Node<>(result.value, left.rotateLeft(), result.right);
					}
					result = result.rotateRight();
				}
			}
			return result;
		}

		public static <Type> Node<Type> clone(Node<Type> result)
		{
			if (result != null)
			{
				result = new Node<>(result.value, clone(result.left), clone(result.right));
			}
			return result;
		}

		public static <Type> Node<Type> delete(Node<Type> node, Type value, Comparator<? super Type> comparator)
		{
			Node<Type> result;
			if (node == null)
			{
				result = null;
			}
			else
			{
				int compare = comparator.compare(value, node.value);
				if (compare == 0)
				{
					if (node.left == null)
					{
						result = node.right;
					}
					else
					{
						if (node.right == null)
						{
							result = node.left;
						}
						else
						{
							Node<Type> first = first(node.right);
							result = new Node<>(first.value, node.left, delete(node.right, first.value, comparator));
						}
					}
				}
				else
				{
					if (compare < 0)
					{
						result = new Node<>(node.value, delete(node.left, value, comparator), node.right);
					}
					else
					{
						result = new Node<>(node.value, node.left, delete(node.right, value, comparator));
					}
				}
				result = balance(result);
			}
			return result;
		}

		public static <Type> Node<Type> first(Node<Type> result)
		{
			while (result.left != null)
			{
				result = result.left;
			}
			return result;
		}

		public static <Type> Node<Type> get(Node<Type> node, Type value, Comparator<? super Type> comparator)
		{
			Node<Type> result;
			if (node == null)
			{
				result = null;
			}
			else
			{
				int compare = comparator.compare(value, node.value);
				if (compare == 0)
				{
					result = node;
				}
				else
				{
					if (compare < 0)
					{
						result = get(node.left, value, comparator);
					}
					else
					{
						result = get(node.right, value, comparator);
					}
				}
			}
			return result;
		}

		public static <Type> Node<Type> head(Node<Type> node, Type value, Comparator<? super Type> comparator)
		{
			Node<Type> result;
			if (node == null)
			{
				result = null;
			}
			else
			{
				int compare = comparator.compare(value, node.value);
				if (compare == 0)
				{
					result = node.left;
				}
				else
				{
					if (compare < 0)
					{
						result = head(node.left, value, comparator);
					}
					else
					{
						result = new Node<>(node.value, node.left, head(node.right, value, comparator));
					}
				}
				result = balance(result);
			}
			return result;
		}

		public static int height(Node node)
		{
			return node == null ? 0 : node.height;
		}

		public static <Type> Node<Type> insert(Node<Type> node, Type value, Comparator<? super Type> comparator)
		{
			Node<Type> result;
			if (node == null)
			{
				result = new Node<>(value, null, null);
			}
			else
			{
				int compare = comparator.compare(value, node.value);
				if (compare == 0)
				{
					result = new Node<>(value, node.left, node.right);
					;
				}
				else
				{
					if (compare < 0)
					{
						result = new Node<>(node.value, insert(node.left, value, comparator), node.right);
					}
					else
					{
						result = new Node<>(node.value, node.left, insert(node.right, value, comparator));
					}
				}
				result = balance(result);
			}
			return result;
		}

		public static <Type> Node<Type> last(Node<Type> result)
		{
			while (result.right != null)
			{
				result = result.right;
			}
			return result;
		}

		public static int size(Node node)
		{
			return node == null ? 0 : node.size;
		}

		public static <Type> Node<Type> tail(Node<Type> node, Type value, Comparator<? super Type> comparator)
		{
			Node<Type> result;
			if (node == null)
			{
				result = null;
			}
			else
			{
				int compare = comparator.compare(value, node.value);
				if (compare == 0)
				{
					result = new Node<>(node.value, null, node.right);
				}
				else
				{
					if (compare < 0)
					{
						result = new Node<>(node.value, tail(node.left, value, comparator), node.right);
					}
					else
					{
						result = tail(node.right, value, comparator);
					}
				}
				result = balance(result);
			}
			return result;
		}

		public static <Type> void traverseOrderIn(Node<Type> node, Consumer<Type> consumer)
		{
			if (node != null)
			{
				traverseOrderIn(node.left, consumer);
				consumer.accept(node.value);
				traverseOrderIn(node.right, consumer);
			}
		}

		public final Type value;
		public final Node<Type> left;
		public final Node<Type> right;
		public final int size;
		private final int height;

		public Node(Type value, Node<Type> left, Node<Type> right)
		{
			this.value = value;
			this.left = left;
			this.right = right;
			this.size = 1 + size(left) + size(right);
			this.height = 1 + Math.max(height(left), height(right));
		}

		public Node<Type> rotateLeft()
		{
			Node<Type> left = new Node<>(this.value, this.left, this.right.left);
			return new Node<>(this.right.value, left, this.right.right);
		}

		public Node<Type> rotateRight()
		{
			Node<Type> right = new Node<>(this.value, this.left.right, this.right);
			return new Node<>(this.left.value, this.left.left, right);
		}
	}

	public static class SortedSetAVL<Type> implements SortedSet<Type>
	{
		public Comparator<? super Type> comparator;
		public Node<Type> root;

		private SortedSetAVL(Comparator<? super Type> comparator, Node<Type> root)
		{
			this.comparator = comparator;
			this.root = root;
		}

		public SortedSetAVL(Comparator<? super Type> comparator)
		{
			this(comparator, null);
		}

		public SortedSetAVL(Collection<? extends Type> collection, Comparator<? super Type> comparator)
		{
			this(comparator, null);
			this.addAll(collection);
		}

		public SortedSetAVL(SortedSetAVL<Type> sortedSetAVL)
		{
			this(sortedSetAVL.comparator, Node.clone(sortedSetAVL.root));
		}

		@Override
		public void clear()
		{
			this.root = null;
		}

		@Override
		public Comparator<? super Type> comparator()
		{
			return this.comparator;
		}

		public Type get(Type value)
		{
			Node<Type> node = Node.get(this.root, value, this.comparator);
			return node == null ? null : node.value;
		}

		@Override
		public SortedSetAVL<Type> subSet(Type valueStart, Type valueEnd)
		{
			return tailSet(valueStart).headSet(valueEnd);
		}

		@Override
		public SortedSetAVL<Type> headSet(Type valueEnd)
		{
			return new SortedSetAVL<>(this.comparator, Node.head(this.root, valueEnd, this.comparator));
		}

		@Override
		public SortedSetAVL<Type> tailSet(Type valueStart)
		{
			return new SortedSetAVL<>(this.comparator, Node.tail(this.root, valueStart, this.comparator));
		}

		@Override
		public Type first()
		{
			return Node.first(this.root).value;
		}

		@Override
		public Type last()
		{
			return Node.last(this.root).value;
		}

		@Override
		public int size()
		{
			return this.root == null ? 0 : this.root.size;
		}

		@Override
		public boolean isEmpty()
		{
			return this.root == null;
		}

		@Override
		public boolean contains(Object value)
		{
			return Node.get(this.root, (Type) value, this.comparator) != null;
		}

		@Override
		public Iterator<Type> iterator()
		{
			Stack<Node<Type>> path = new Stack<>();

			return new Iterator<Type>()
			{
				{
					push(SortedSetAVL.this.root);
				}

				public void push(Node<Type> node)
				{
					while (node != null)
					{
						path.push(node);
						node = node.left;
					}
				}

				@Override
				public boolean hasNext()
				{
					return !path.isEmpty();
				}

				@Override
				public Type next()
				{
					if (path.isEmpty())
					{
						throw new NoSuchElementException();
					}
					else
					{
						Node<Type> node = path.peek();
						Type result = node.value;
						if (node.right != null)
						{
							push(node.right);
						}
						else
						{
							do
							{
								node = path.pop();
							}
							while (!path.isEmpty() && path.peek().right == node);
						}
						return result;
					}
				}
			};
		}

		@Override
		public Object[] toArray()
		{
			List<Object> list = new ArrayList<>();
			Node.traverseOrderIn(this.root, list::add);
			return list.toArray();
		}

		@Override
		public <T> T[] toArray(T[] ts)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public boolean add(Type value)
		{
			int sizeBefore = size();
			this.root = Node.insert(this.root, value, this.comparator);
			return sizeBefore != size();
		}

		@Override
		public boolean remove(Object value)
		{
			int sizeBefore = size();
			this.root = Node.delete(this.root, (Type) value, this.comparator);
			return sizeBefore != size();
		}

		@Override
		public boolean containsAll(Collection<?> collection)
		{
			return collection.stream()
					.allMatch(this::contains);
		}

		@Override
		public boolean addAll(Collection<? extends Type> collection)
		{
			return collection.stream()
					.map(this::add)
					.reduce(true, (x, y) -> x | y);
		}

		@Override
		public boolean retainAll(Collection<?> collection)
		{
			SortedSetAVL<Type> set = new SortedSetAVL<>(this.comparator);
			collection.stream()
					.map(element -> (Type) element)
					.filter(this::contains)
					.forEach(set::add);
			boolean result = size() != set.size();
			this.root = set.root;
			return result;
		}

		@Override
		public boolean removeAll(Collection<?> collection)
		{
			return collection.stream()
					.map(this::remove)
					.reduce(true, (x, y) -> x | y);
		}

		@Override
		public String toString()
		{
			return "{" + E_418.toString(this, ", ") + "}";
		}
	}

	public static class SortedMapAVL<TypeKey, TypeValue> implements SortedMap<TypeKey, TypeValue>
	{
		public final Comparator<? super TypeKey> comparator;
		public final SortedSetAVL<Entry<TypeKey, TypeValue>> entrySet;

		public SortedMapAVL(Comparator<? super TypeKey> comparator)
		{
			this(comparator, new SortedSetAVL<>((entry0, entry1) -> comparator.compare(entry0.getKey(), entry1.getKey())));
		}

		private SortedMapAVL(Comparator<? super TypeKey> comparator, SortedSetAVL<Entry<TypeKey, TypeValue>> entrySet)
		{
			this.comparator = comparator;
			this.entrySet = entrySet;
		}

		@Override
		public Comparator<? super TypeKey> comparator()
		{
			return this.comparator;
		}

		@Override
		public SortedMapAVL<TypeKey, TypeValue> subMap(TypeKey keyStart, TypeKey keyEnd)
		{
			return new SortedMapAVL<>(this.comparator, this.entrySet.subSet(new AbstractMap.SimpleEntry<>(keyStart, null), new AbstractMap.SimpleEntry<>(keyEnd, null)));
		}

		@Override
		public SortedMapAVL<TypeKey, TypeValue> headMap(TypeKey keyEnd)
		{
			return new SortedMapAVL<>(this.comparator, this.entrySet.headSet(new AbstractMap.SimpleEntry<>(keyEnd, null)));
		}

		@Override
		public SortedMapAVL<TypeKey, TypeValue> tailMap(TypeKey keyStart)
		{
			return new SortedMapAVL<>(this.comparator, this.entrySet.tailSet(new AbstractMap.SimpleEntry<>(keyStart, null)));
		}

		public Entry<TypeKey, TypeValue> firstEntry()
		{
			return this.entrySet.first();
		}

		@Override
		public TypeKey firstKey()
		{
			return firstEntry().getKey();
		}

		public Entry<TypeKey, TypeValue> lastEntry()
		{
			return this.entrySet.last();
		}

		@Override
		public TypeKey lastKey()
		{
			return lastEntry().getKey();
		}

		@Override
		public int size()
		{
			return this.entrySet().size();
		}

		@Override
		public boolean isEmpty()
		{
			return this.entrySet.isEmpty();
		}

		@Override
		public boolean containsKey(Object key)
		{
			return this.entrySet().contains(new AbstractMap.SimpleEntry<>((TypeKey) key, null));
		}

		@Override
		public boolean containsValue(Object value)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public TypeValue get(Object key)
		{
			Entry<TypeKey, TypeValue> entry = new AbstractMap.SimpleEntry<>((TypeKey) key, null);
			entry = this.entrySet.get(entry);
			return entry == null ? null : entry.getValue();
		}

		@Override
		public TypeValue put(TypeKey key, TypeValue value)
		{
			TypeValue result = get(key);
			Entry<TypeKey, TypeValue> entry = new AbstractMap.SimpleEntry<>(key, value);
			this.entrySet().add(entry);
			return result;
		}

		@Override
		public TypeValue remove(Object key)
		{
			TypeValue result = get(key);
			Entry<TypeKey, TypeValue> entry = new AbstractMap.SimpleEntry<>((TypeKey) key, null);
			this.entrySet.remove(entry);
			return result;
		}

		@Override
		public void putAll(Map<? extends TypeKey, ? extends TypeValue> map)
		{
			map.entrySet()
					.forEach(entry -> put(entry.getKey(), entry.getValue()));
		}

		@Override
		public void clear()
		{
			this.entrySet.clear();
		}

		@Override
		public Set<TypeKey> keySet()
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public Collection<TypeValue> values()
		{
			return new Collection<TypeValue>()
			{
				@Override
				public int size()
				{
					return SortedMapAVL.this.entrySet.size();
				}

				@Override
				public boolean isEmpty()
				{
					return SortedMapAVL.this.entrySet.isEmpty();
				}

				@Override
				public boolean contains(Object value)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public Iterator<TypeValue> iterator()
				{
					return new Iterator<TypeValue>()
					{
						Iterator<Entry<TypeKey, TypeValue>> iterator = SortedMapAVL.this.entrySet.iterator();

						@Override
						public boolean hasNext()
						{
							return this.iterator.hasNext();
						}

						@Override
						public TypeValue next()
						{
							return this.iterator.next().getValue();
						}
					};
				}

				@Override
				public Object[] toArray()
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public <T> T[] toArray(T[] ts)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean add(TypeValue typeValue)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean remove(Object o)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean containsAll(Collection<?> collection)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean addAll(Collection<? extends TypeValue> collection)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean removeAll(Collection<?> collection)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public boolean retainAll(Collection<?> collection)
				{
					throw new UnsupportedOperationException();
				}

				@Override
				public void clear()
				{
					throw new UnsupportedOperationException();
				}
			};
		}

		@Override
		public SortedSetAVL<Entry<TypeKey, TypeValue>> entrySet()
		{
			return this.entrySet;
		}

		@Override
		public String toString()
		{
			return this.entrySet().toString();
		}
	}

	public static class FIFO<Type>
	{
		public SingleLinkedList<Type> start;
		public SingleLinkedList<Type> end;

		public FIFO()
		{
			this.start = null;
			this.end = null;
		}

		public boolean isEmpty()
		{
			return this.start == null;
		}

		public Type peek()
		{
			return this.start.element;
		}

		public Type pop()
		{
			Type result = this.start.element;
			this.start = this.start.next;
			return result;
		}

		public void push(Type element)
		{
			SingleLinkedList<Type> list = new SingleLinkedList<>(element, null);
			if (this.start == null)
			{
				this.start = list;
				this.end = list;
			}
			else
			{
				this.end.next = list;
				this.end = list;
			}
		}
	}

	public static class MapCount<Type> extends SortedMapAVL<Type, Long>
	{
		private int count;

		public MapCount(Comparator<? super Type> comparator)
		{
			super(comparator);
			this.count = 0;
		}

		public long add(Type key, Long delta)
		{
			long result;
			if (delta > 0)
			{
				Long value = get(key);
				if (value == null)
				{
					value = delta;
				}
				else
				{
					value += delta;
				}
				put(key, value);
				result = delta;
			}
			else
			{
				result = 0;
			}
			this.count += result;
			return result;
		}

		public int count()
		{
			return this.count;
		}

		public List<Type> flatten()
		{
			List<Type> result = new ArrayList<>();
			for (Entry<Type, Long> entry : entrySet())
			{
				for (long index = 0; index < entry.getValue(); index++)
				{
					result.add(entry.getKey());
				}
			}
			return result;
		}

		@Override
		public void putAll(Map<? extends Type, ? extends Long> map)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public Long remove(Object key)
		{
			Long result = super.remove(key);
			this.count -= result;
			return result;
		}

		public long remove(Type key, Long delta)
		{
			long result;
			if (delta > 0)
			{
				Long value = get(key) - delta;
				if (value <= 0)
				{
					result = delta + value;
					remove(key);
				}
				else
				{
					result = delta;
					put(key, value);
				}
			}
			else
			{
				result = 0;
			}
			this.count -= result;
			return result;
		}

		@Override
		public SortedMapAVL<Type, Long> subMap(Type keyStart, Type keyEnd)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public SortedMapAVL<Type, Long> headMap(Type keyEnd)
		{
			throw new UnsupportedOperationException();
		}

		@Override
		public SortedMapAVL<Type, Long> tailMap(Type keyStart)
		{
			throw new UnsupportedOperationException();
		}
	}

	public static class MapSet<TypeKey, TypeValue> extends SortedMapAVL<TypeKey, SortedSetAVL<TypeValue>> implements Iterable<TypeValue>
	{
		private Comparator<? super TypeValue> comparatorValue;

		public MapSet(Comparator<? super TypeKey> comparatorKey, Comparator<? super TypeValue> comparatorValue)
		{
			super(comparatorKey);
			this.comparatorValue = comparatorValue;
		}

		public MapSet(Comparator<? super TypeKey> comparatorKey, SortedSetAVL<Entry<TypeKey, SortedSetAVL<TypeValue>>> entrySet, Comparator<? super TypeValue> comparatorValue)
		{
			super(comparatorKey, entrySet);
			this.comparatorValue = comparatorValue;
		}

		public TypeValue firstValue()
		{
			TypeValue result;
			Entry<TypeKey, SortedSetAVL<TypeValue>> firstEntry = firstEntry();
			if (firstEntry == null)
			{
				result = null;
			}
			else
			{
				result = firstEntry.getValue().first();
			}
			return result;
		}

		public Iterator<TypeValue> iterator()
		{
			return new Iterator<TypeValue>()
			{
				Iterator<SortedSetAVL<TypeValue>> iteratorValues = values().iterator();
				Iterator<TypeValue> iteratorValue = null;

				@Override
				public boolean hasNext()
				{
					return iteratorValues.hasNext() || (iteratorValue != null && iteratorValue.hasNext());
				}

				@Override
				public TypeValue next()
				{
					if (iteratorValue == null || !iteratorValue.hasNext())
					{
						iteratorValue = iteratorValues.next().iterator();
					}
					return iteratorValue.next();
				}
			};
		}

		public TypeValue lastValue()
		{
			TypeValue result;
			Entry<TypeKey, SortedSetAVL<TypeValue>> lastEntry = lastEntry();
			if (lastEntry == null)
			{
				result = null;
			}
			else
			{
				result = lastEntry.getValue().last();
			}
			return result;
		}

		public boolean add(TypeKey key, TypeValue value)
		{
			SortedSetAVL<TypeValue> set = computeIfAbsent(key, k -> new SortedSetAVL<>(comparatorValue));
			return set.add(value);
		}

		public boolean removeSet(TypeKey key, TypeValue value)
		{
			boolean result;
			SortedSetAVL<TypeValue> set = get(key);
			if (set == null)
			{
				result = false;
			}
			else
			{
				result = set.remove(value);
				if (set.size() == 0)
				{
					remove(key);
				}
			}
			return result;
		}

		@Override
		public MapSet<TypeKey, TypeValue> headMap(TypeKey keyEnd)
		{
			return new MapSet<>(this.comparator, this.entrySet.headSet(new AbstractMap.SimpleEntry<>(keyEnd, null)), this.comparatorValue);
		}

		@Override
		public MapSet<TypeKey, TypeValue> tailMap(TypeKey keyStart)
		{
			return new MapSet<>(this.comparator, this.entrySet.tailSet(new AbstractMap.SimpleEntry<>(keyStart, null)), this.comparatorValue);
		}
	}

	static class IteratorBuffer<Type>
	{
		private Iterator<Type> iterator;
		private List<Type> list;

		public IteratorBuffer(Iterator<Type> iterator)
		{
			this.iterator = iterator;
			this.list = new ArrayList<Type>();
		}

		public Iterator<Type> iterator()
		{
			return new Iterator<Type>()
			{
				int index = 0;

				@Override
				public boolean hasNext()
				{
					return this.index < list.size() || iterator().hasNext();
				}

				@Override
				public Type next()
				{
					if (list.size() <= this.index)
					{
						list.add(iterator.next());
					}
					Type result = list.get(index);
					index += 1;
					return result;
				}
			};
		}
	}

	public static <Type> List<List<Type>> permutations(List<Type> list)
	{
		List<List<Type>> result = new ArrayList<>();
		result.add(new ArrayList<>());
		for (Type element : list)
		{
			List<List<Type>> permutations = result;
			result = new ArrayList<>();
			for (List<Type> permutation : permutations)
			{
				for (int index = 0; index <= permutation.size(); index++)
				{
					List<Type> permutationNew = new ArrayList<>(permutation);
					permutationNew.add(index, element);
					result.add(permutationNew);
				}
			}
		}
		return result;
	}

	public static List<List<Integer>> combinations(int n, int k)
	{
		List<List<Integer>> result = new ArrayList<>();
		if (k == 0)
		{
		}
		else
		{
			if (k == 1)
			{
				List<Integer> combination = new ArrayList<>();
				combination.add(n);
				result.add(combination);
			}
			else
			{
				for (int index = 0; index <= n; index++)
				{
					for (List<Integer> combination : combinations(n - index, k - 1))
					{
						combination.add(index);
						result.add(combination);
					}
				}
			}
		}
		return result;
	}

	public static <Type> int compare(Iterator<Type> iterator0, Iterator<Type> iterator1, Comparator<Type> comparator)
	{
		int result = 0;
		while (result == 0 && iterator0.hasNext() && iterator1.hasNext())
		{
			result = comparator.compare(iterator0.next(), iterator1.next());
		}
		if (result == 0)
		{
			if (iterator1.hasNext())
			{
				result = -1;
			}
			else
			{
				if (iterator0.hasNext())
				{
					result = 1;
				}
			}
		}
		return result;
	}

	public static <Type> int compare(Iterable<Type> iterable0, Iterable<Type> iterable1, Comparator<Type> comparator)
	{
		return compare(iterable0.iterator(), iterable1.iterator(), comparator);
	}

	private static String nextString() throws IOException
	{
		while ((stringTokenizer == null) || (!stringTokenizer.hasMoreTokens()))
		{
			stringTokenizer = new StringTokenizer(bufferedReader.readLine());
		}
		return stringTokenizer.nextToken();
	}

	private static String[] nextStrings(int n) throws IOException
	{
		String[] result = new String[n];
		{
			for (int index = 0; index < n; index++)
			{
				result[index] = nextString();
			}
		}
		return result;
	}

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

	public static int[] nextInts(int n) throws IOException
	{
		int[] result = new int[n];
		{
			for (int index = 0; index < n; index++)
			{
				result[index] = nextInt();
			}
		}
		return result;
	}

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

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

	public static long[] nextLongs(int n) throws IOException
	{
		long[] result = new long[n];
		{
			for (int index = 0; index < n; index++)
			{
				result[index] = nextLong();
			}
		}
		return result;
	}

	public static String nextLine() throws IOException
	{
		return bufferedReader.readLine();
	}

	public static void close()
	{
		out.close();
	}

	public static int binarySearchMinimum(Function<Integer, Boolean> filter, int start, int end)
	{
		int result;
		if (start == end)
		{
			result = end;
		}
		else
		{
			int middle = start + (end - start) / 2;
			if (filter.apply(middle))
			{
				result = binarySearchMinimum(filter, start, middle);
			}
			else
			{
				result = binarySearchMinimum(filter, middle + 1, end);
			}
		}
		return result;
	}

	public static int binarySearchMaximum(Function<Integer, Boolean> filter, int start, int end)
	{
		return -binarySearchMinimum(x -> filter.apply(-x), -end, -start);
	}

	public static long divideCeil(long x, long y)
	{
		return (x + y - 1) / y;
	}

	public static Set<Long> divisors(long n)
	{
		SortedSetAVL<Long> result = new SortedSetAVL<>(Comparator.naturalOrder());
		result.add(1L);
		for (Long factor : factors(n))
		{
			SortedSetAVL<Long> divisors = new SortedSetAVL<>(result);
			for (Long divisor : result)
			{
				divisors.add(divisor * factor);
			}
			result = divisors;
		}
		return result;
	}

	public static BigInteger facultyBig(int n)
	{
		BigInteger result = BigInteger.ONE;
		for (int index = 2; index <= n; index++)
		{
			result = result.multiply(BigInteger.valueOf(index));
		}
		return result;
	}

	public static long faculty(int n)
	{
		long result = 1;
		for (int index = 2; index <= n; index++)
		{
			result *= index;
		}
		return result;
	}

	public static LinkedList<Long> factors(long n)
	{
		LinkedList<Long> result = new LinkedList<>();
		Iterator<Long> primes = ITERATOR_BUFFER_PRIME.iterator();
		Long prime;
		while (n > 1 && (prime = primes.next()) * prime <= n)
		{
			while (n % prime == 0)
			{
				result.add(prime);
				n /= prime;
			}
		}
		if (n > 1)
		{
			result.add(n);
		}
		return result;
	}

	public static long gcd(long a, long b)
	{
		while (a != 0 && b != 0)
		{
			if (a > b)
			{
				a %= b;
			}
			else
			{
				b %= a;
			}
		}
		return a + b;
	}

	public static long[] generatePOWER2()
	{
		long[] result = new long[63];
		for (int x = 0; x < result.length; x++)
		{
			result[x] = 1L << x;
		}
		return result;
	}

	public static BigInteger[] generateFacultyBig()
	{
		BigInteger[] result = new BigInteger[50];
		for (int x = 0; x < result.length; x++)
		{
			result[x] = facultyBig(x);
		}
		return result;
	}

	public static boolean isPrime(long x)
	{
		boolean result = x > 1;
		Iterator<Long> iterator = ITERATOR_BUFFER_PRIME.iterator();
		Long prime;
		while ((prime = iterator.next()) * prime <= x)
		{
			result &= x % prime > 0;
		}
		return result;
	}

	public static long knapsack(List<Tuple3<Long, Integer, Integer>> itemsValueWeightCount, int weightMaximum)
	{
		long[] valuesMaximum = new long[weightMaximum + 1];
		for (Tuple3<Long, Integer, Integer> itemValueWeightCount : itemsValueWeightCount)
		{
			long itemValue = itemValueWeightCount.v0;
			int itemWeight = itemValueWeightCount.v1;
			int itemCount = itemValueWeightCount.v2;
			for (int weight = weightMaximum; 0 <= weight; weight--)
			{
				for (int index = 1; index <= itemCount && 0 <= weight - index * itemWeight; index++)
				{
					valuesMaximum[weight] = Math.max(valuesMaximum[weight], valuesMaximum[weight - index * itemWeight] + index * itemValue);
				}
			}
		}
		long result = 0;
		for (long valueMaximum : valuesMaximum)
		{
			result = Math.max(result, valueMaximum);
		}
		return result;
	}

	public static boolean knapsackPossible(List<Tuple2<Integer, Integer>> itemsWeightCount, int weightMaximum)
	{
		boolean[] weightPossible = new boolean[weightMaximum + 1];
		weightPossible[0] = true;
		int weightLargest = 0;
		for (Tuple2<Integer, Integer> itemWeightCount : itemsWeightCount)
		{
			int itemWeight = itemWeightCount.v0;
			int itemCount = itemWeightCount.v1;
			for (int weightStart = 0; weightStart < itemWeight; weightStart++)
			{
				int count = 0;
				for (int weight = weightStart; weight <= weightMaximum && (0 < count || weight <= weightLargest); weight += itemWeight)
				{
					if (weightPossible[weight])
					{
						count = itemCount;
					}
					else
					{
						if (0 < count)
						{
							weightPossible[weight] = true;
							weightLargest = weight;
							count -= 1;
						}
					}
				}
			}
		}
		return weightPossible[weightMaximum];
	}

	public static long lcm(int a, int b)
	{
		return a * b / gcd(a, b);
	}

	public static <T> List<T> permutation(long p, List<T> x)
	{
		List<T> copy = new ArrayList<>();
		for (int index = 0; index < x.size(); index++)
		{
			copy.add(x.get(index));
		}
		List<T> result = new ArrayList<>();
		for (int indexTo = 0; indexTo < x.size(); indexTo++)
		{
			int indexFrom = (int) p % copy.size();
			p = p / copy.size();
			result.add(copy.remove(indexFrom));
		}
		return result;
	}

	public static <Type> String toString(Iterator<Type> iterator, String separator)
	{
		StringBuilder stringBuilder = new StringBuilder();
		if (iterator.hasNext())
		{
			stringBuilder.append(iterator.next());
		}
		while (iterator.hasNext())
		{
			stringBuilder.append(separator);
			stringBuilder.append(iterator.next());
		}
		return stringBuilder.toString();
	}

	public static <Type> String toString(Iterator<Type> iterator)
	{
		return toString(iterator, " ");
	}

	public static <Type> String toString(Iterable<Type> iterable, String separator)
	{
		return toString(iterable.iterator(), separator);
	}

	public static <Type> String toString(Iterable<Type> iterable)
	{
		return toString(iterable, " ");
	}

	public static Stream<BigInteger> streamFibonacci()
	{
		return Stream.generate(new Supplier<BigInteger>()
		{
			private BigInteger n0 = BigInteger.ZERO;
			private BigInteger n1 = BigInteger.ONE;

			@Override
			public BigInteger get()
			{
				BigInteger result = n0;
				n0 = n1;
				n1 = result.add(n0);
				return result;
			}
		});
	}

	public static Stream<Long> streamPrime(int sieveSize)
	{
		return Stream.generate(new Supplier<Long>()
		{
			private boolean[] isPrime = new boolean[sieveSize];
			private long sieveOffset = 2;
			private List<Long> primes = new ArrayList<>();
			private int index = 0;

			public void filter(long prime, boolean[] result)
			{
				if (prime * prime < this.sieveOffset + sieveSize)
				{
					long remainingStart = this.sieveOffset % prime;
					long start = remainingStart == 0 ? 0 : prime - remainingStart;
					for (long index = start; index < sieveSize; index += prime)
					{
						result[(int) index] = false;
					}
				}
			}

			public void generatePrimes()
			{
				Arrays.fill(this.isPrime, true);
				this.primes.forEach(prime -> filter(prime, isPrime));
				for (int index = 0; index < sieveSize; index++)
				{
					if (isPrime[index])
					{
						this.primes.add(this.sieveOffset + index);
						filter(this.sieveOffset + index, isPrime);
					}
				}
				this.sieveOffset += sieveSize;
			}

			@Override
			public Long get()
			{
				while (this.primes.size() <= this.index)
				{
					generatePrimes();
				}
				Long result = this.primes.get(this.index);
				this.index += 1;
				return result;
			}
		});
	}

	public static long totient(long n)
	{
		Set<Long> factors = new SortedSetAVL<>(factors(n), Comparator.naturalOrder());
		long result = n;
		for (long p : factors)
		{
			result -= result / p;
		}
		return result;
	}

	public static void main(String[] args)
	{
		try
		{
			solve();
		} catch (IOException exception)
		{
			exception.printStackTrace();
		}
		close();
	}

	public static void add(int p1, int p2, int c1, int c2, long count, long[][][][] result)
	{
		if (p1 >= 0 && p2 >= 0 && c1 >= 0 && c2 >= 0 && count > 0)
		{
			if (p1 < result.length && p2 < result[p1].length && c1 < result[p1][p2].length && c2 < result[p1][p2][c1].length)
			{
				result[p1][p2][c1][c2] += count;
			}
		}
	}

	public static void addPrevious(int p1, int p2, int c1, int c2, long count, long[][][][] result)
	{
		add(p1 - 1, p2, c1, c2, p1 * count, result);
		add(p1 + 1, p2 - 1, c1, c2, p2 * count, result);
	}

	public static void next(int d, long count, int p1, int p2, int c1, int c2, long[][][][] result)
	{
		if (p1 == 0 && p2 == 0)
		{
			if (d == 2)
			{
				addPrevious(c1, c2, 1, 0, count, result);
			}
			else
			{
				addPrevious(c1, c2, 0, 1, count, result);
			}
		}

		if (d == 2)
		{
			addPrevious(p1, p2, c1 + 1, c2, count, result);

			addPrevious(p1, p2, c1 - 1, c2, c1 * count, result);
			addPrevious(p1, p2, c1 + 1, c2 - 1, c2 * count, result);
		}
		else
		{
			addPrevious(p1, p2, c1, c2 + 1, count, result);

			addPrevious(p1, p2, c1, c2, c1 * count, result);
			addPrevious(p1, p2, c1 + 2, c2 - 1, c2 * count, result);

			addPrevious(p1, p2, c1 - 2, c2, c1 * (c1 - 1) / 2 * count, result);
			addPrevious(p1, p2, c1, c2 - 1, c1 * c2 * count, result);
			addPrevious(p1, p2, c1 + 2, c2 - 2, c2 * (c2 - 1) / 2 * count, result);
		}
	}

	public static long solve(int[] d)
	{
		long[][][][] count = new long[d.length / 2 + 1][d.length / 2 + 1][d.length / 2 + 1][d.length / 2 + 1];
		if (d[0] == 2)
		{
			if (d[1] == 2)
			{
				count[1][0][1][0] = 1;
			}
			else
			{
				count[1][0][0][1] = 1;
			}
		}
		else
		{
			if (d[1] == 2)
			{
				count[0][1][1][0] = 1;
			}
			else
			{
				count[0][1][0][1] = 1;
			}
		}
		for (int u = 2; u < d.length; u++)
		{
			long[][][][] countNext = new long[d.length / 2 + 1][d.length / 2 + 1][d.length / 2 + 1][d.length / 2 + 1];
			for (int p1 = 0; p1 <= d.length / 2; p1++)
			{
				for (int p2 = 0; p2 <= d.length / 2 && p1 + p2 < d.length; p2++)
				{
					for (int c1 = 0; c1 <= d.length / 2 && p1 + p2 + c1 < d.length; c1++)
					{
						for (int c2 = 0; c2 <= d.length / 2 && p1 + p2 + c1 + c2 < d.length; c2++)
						{
							next(d[u], count[p1][p2][c1][c2] % BIG, p1, p2, c1, c2, countNext);
						}
					}
				}
			}
			count = countNext;
		}
		return count[0][0][0][0] % BIG;
	}

	public static void solve() throws IOException
	{
		int n = nextInt();
		int[] d = nextInts(n);
		out.println(solve(d));
	}
}


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

public class WrongAnswerTest233 {
    public static int MAXN = 200005;
    public static long MOD = 998244353;
    public static long[] fact;
    public static long[] invfact;
    public static long[] pow2;
    public static void main(String[] args) throws IOException{
        BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));
        StringTokenizer st = new StringTokenizer(f.readLine());
        int n = Integer.parseInt(st.nextToken());
        long k = Long.parseLong(st.nextToken());
        if(n == 1){
            out.println(0);
            out.close();
            return;
        }
        if(k == 1){
            out.println(0);
            out.close();
            return;
        }
        long[] arr = new long[n];
        st = new StringTokenizer(f.readLine());
        for(int i = 0; i < n; i++) arr[i] = Long.parseLong(st.nextToken());
        fact = new long[MAXN];
        invfact = new long[MAXN];
        pow2 = new long[MAXN];
        fact[0] = 1;
        invfact[0] = 1;
        pow2[0] = 1;
        for(int i = 1; i < MAXN; i++){
            pow2[i] = add(pow2[i-1], pow2[i-1]);
            fact[i] = mult(fact[i-1], i);
        }
        invfact[MAXN-1] = inverse(fact[MAXN-1]);
        for(int i = MAXN-2; i >= 1; i--){
            invfact[i] = mult(invfact[i+1], i+1);
        }
        int cnt = 0;
        for(int i = 0; i < n; i++) if(arr[i] != arr[(i+1)%n]) cnt++;
        long multiplier = pow(k, n-cnt);
        long ans = 0;
        for(int i = 1; i <= cnt; i++){
            long res = multiplier;
            res = mult(res, ncr(cnt, i));
            if(i != cnt){
                res = mult(res, pow(k-2, cnt-i));
            }
            long currval = pow2[i-1];
            if(i % 2 == 0) currval = add(currval, mult(MOD-1, mult(invfact[2], ncr(i, i/2))));
            res = mult(res, currval);
            ans = add(ans, res);
        }
        out.println(ans);
        out.close();

    }
    public static long add(long a, long b){
        return((a+b)%MOD+MOD)%MOD;
    }
    public static long mult(long a, long b){
        return((a*b)%MOD+MOD)%MOD;
    }
    public static long pow(long a, long b){
        long ans = 1;
        while(b > 0){
            if((b&1) == 1) ans = mult(ans, a);
            a = mult(a, a);
            b>>=1;
        }
        return ans;
    }
    public static long ncr(long a, long b){
        if(a<0) return 0;
        if(b<0) return 0;
        if(a<b) return 0;
        if(b==0) return 1;
        if(a==b) return 1;
        return mult(fact[(int)a],mult(invfact[(int)b],invfact[(int)(a-b)]));
    }
    public static long inverse(long a){
        return pow(a, MOD-2);
    }
}


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

public class Main {

    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

        FastReader() {
            br = new BufferedReader(new
                                    InputStreamReader(System.in));
        }

        FastReader(final InputStream is) {
            if (is != null)
                br = new BufferedReader(new
                                        InputStreamReader(is));
            else new FastReader();
        }

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

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

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

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

        String nextLine() throws IOException {
            return br.readLine();
        }
    }

    public static void main(String args[]) throws Exception {
        final FastReader reader = new FastReader();
        PrintWriter writer = new PrintWriter(new BufferedOutputStream(System.out));
        int n = reader.nextInt();
        double p = reader.nextDouble();
        int t = reader.nextInt();

        //state is P[n][t] n ppl in esc at time t
        //t=0 0
        //writer.println("n=" + n + ", p=" + p + ", t=" + t);
        double[][] P = new double[n + 1 ][t + 1];
        for (int i = 0; i <= n; i++) P[i][0] = 0;
        P[0][0] = 1;
        for (int i = 1; i <= t; i++) {
            P[0][i] = P[0][i - 1] * (1 - p);
        }
        for (int m = 1; m <= n; m++) {
            int time = 1;
            while (time <= t) {
                if (m >= n) P[m][time] = P[m][time - 1] + P[m-1][time-1] * p;
                else P[m][time] = P[m][time - 1]*(1-p)  + P[m - 1][time - 1] * p;
                time++;
            }
        }
        //for (double[] r : P) writer.println(Arrays.toString(r));
        double ans = 0.000000d;
        for (int i = 0; i <= n; i++) {
            ans += P[i][t] * i;
        }
        writer.printf("%.06f\n", ans);
        writer.close();
    }

    static int pow2(int v) {
        v--;
        v |= v >> 1;
        v |= v >> 2;
        v |= v >> 4;
        v |= v >> 8;
        v |= v >> 16;
        v++;
        return v;
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.math.BigInteger;
import java.util.Random;
import java.util.StringTokenizer;

public class D {
    public static void main(String[] args) {
        FastScanner sc = new FastScanner();

        long a1 = sc.nextLong();
        long b1 = sc.nextLong();
        long a2 = sc.nextLong();
        long b2 = sc.nextLong();
        long left = sc.nextLong();
        long right = sc.nextLong();

        long lcm = lcm(a1, a2);
        left = Math.max(left, Math.max(b1, b2));

        // a1*x + b1 = a2*y + b2
        // a1*x - a2*y = b1 - b2
        long[] x_y_gcd = solveDiophantine(a1, -a2, b2 - b1);
        if (x_y_gcd == null) {
            System.out.println(0);
        } else {
            BigInteger a1Bi = BigInteger.valueOf(a1);
            BigInteger b1Bi = BigInteger.valueOf(b1);
            BigInteger leftBi = BigInteger.valueOf(left);
            BigInteger rightBi = BigInteger.valueOf(right);
            BigInteger lcmBi = BigInteger.valueOf(lcm);

            BigInteger firstEq = a1Bi.multiply(BigInteger.valueOf(x_y_gcd[0])).add(b1Bi);
            BigInteger diff = leftBi.subtract(firstEq).divide(lcmBi).subtract(BigInteger.ONE);
            firstEq = firstEq.add(diff.multiply(lcmBi));
            while (firstEq.compareTo(leftBi) < 0) {
                firstEq = firstEq.add(lcmBi);
            }
            if (rightBi.compareTo(firstEq) < 0) {
                System.out.println(0);
            } else {
                long count = Math.max(rightBi.subtract(firstEq).divide(lcmBi).longValue() + 1, 0);
                System.out.println(count);
            }
        }
    }

    /**
     * Finds a single solution {x, y} to the LDE a*x + b*y = c.
     * Outputs an array of the form {x, y, d}, where d = GCD(a,b).
     */
    private static long[] solveDiophantine(long a, long b, long c) {
        long[] e = extEuclid(a, b);
        long k = c / e[2];

        //c not divisible by the GCD(a,b) -> no solution
        if (c - k * e[2] != 0)
            return null;

        long[] output = {e[0] * k, e[1] * k, e[2]};
        return output;
    }

    /**
     * Extended Euclidean Algorithm finds {x, y, d}
     * where d=GCD(a,b) and x and y satisfy a*x + b*y = d
     * The output is an array of the form {x, y, d}.
     */
    private static long[] extEuclid(long a, long b) {
        long s0 = 1, s1 = 0, sTemp;
        long t0 = 0, t1 = 1, tTemp;
        long r0 = a, r1 = b, rTemp;
        long q;

        while (r1 != 0) {
            q = r0 / r1;

            rTemp = r1;
            r1 = r0 - q * r1;
            r0 = rTemp;

            sTemp = s1;
            s1 = s0 - q * s1;
            s0 = sTemp;

            tTemp = t1;
            t1 = t0 - q * t1;
            t0 = tTemp;
        }

        long[] output = {s0, t0, r0};
        return output;
    }

    static long lcm(long a, long b) {
        return a / gcd(a, b) * b;
    }

    static long gcd(long a, long b) {
        if (b == 0) return a;
        return gcd(b, a % b);
    }

    public static class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(Reader in) {
            br = new BufferedReader(in);
        }

        public FastScanner() {
            this(new InputStreamReader(System.in));
        }

        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 readNextLine() {
            String str = "";
            try {
                str = br.readLine();
            } catch (IOException e) {
                e.printStackTrace();
            }
            return str;
        }

        int[] readIntArray(int n) {
            int[] a = new int[n];
            for (int idx = 0; idx < n; idx++) {
                a[idx] = nextInt();
            }
            return a;
        }

        long[] readLongArray(int n) {
            long[] a = new long[n];
            for (int idx = 0; idx < n; idx++) {
                a[idx] = nextLong();
            }
            return a;
        }
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.*;

public class D {

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

    void run() throws Exception {
        final int MOD = 1000000007;
        int p = nextInt();
        long k = nextInt();
        DisjointSets set = new DisjointSets(p);
        for (int i = 0; i < p; ++i) {
            set.union(i, (int) (k * i % p));
        }
        HashSet<Integer> countDiff = new HashSet<>();
        for (int i = 0; i < p; ++i) {
            countDiff.add(set.findRoot(i));
        }
        int deg = countDiff.size();
        if (k == 0) {
            deg = p - 1;
        } else if (k != 1) {
            --deg;
        }
        long res = 1;
        for (int i = 0; i < deg; ++i) {
            res = (res * p) % MOD;
        }
        out.print(res);
    }

    public class DisjointSets {

        public DisjointSets(int nVertexes) {
            root = new int[nVertexes];
            rank = new int[nVertexes];
            for (int i = 0; i < nVertexes; ++i) {
                root[i] = i;
                rank[i] = 1;
            }
        }

        public int findRoot(int x) {
            if (root[x] != x) {
                return root[x] = findRoot(root[x]);
            }
            return x;
        }

        public boolean union(int ind, int[][] e) {
            return union(e[ind]);
        }

        public boolean union(int[] e) {
            return union(e[0], e[1]);
        }

        public boolean union(int x, int y) {
            x = findRoot(x);
            y = findRoot(y);
            if (x != y) {
                if (rank[x] > rank[y]) {
                    root[y] = x;
                } else if (rank[x] < rank[y]) {
                    root[x] = y;
                } else {
                    root[x] = y;
                    ++rank[y];
                }
                return true;
            }
            return false;
        }

        private final int[] root;
        private final int[] rank;
    }

//~~~~~~~~~~~~~~~~~~~~~~~~~~~ template ~~~~~~~~~~~~~~~~~~~~~~~~~~~
    int[] nextIntArray(int n) throws IOException {
        int[] res = new int[n];
        for (int i = 0; i < n; ++i) {
            res[i] = nextInt();
        }
        return res;
    }

    int[][] nextIntArray(int nx, int ny) throws IOException {
        int[][] res = new int[nx][ny];
        for (int i = 0; i < nx; ++i) {
            for (int j = 0; j < ny; ++j) {
                res[i][j] = nextInt();
            }
        }
        return res;
    }

    long[] nextLongArray(int n) throws IOException {
        long[] res = new long[n];
        for (int i = 0; i < n; ++i) {
            res[i] = nextLong();
        }
        return res;
    }

    long[][] nextLongArray(int nx, int ny) throws IOException {
        long[][] res = new long[nx][ny];
        for (int i = 0; i < nx; ++i) {
            for (int j = 0; j < ny; ++j) {
                res[i][j] = nextLong();
            }
        }
        return res;
    }

    void fill(int[][] arr, int val) {
        for (int i = 0; i < arr.length; ++i) {
            Arrays.fill(arr[i], val);
        }
    }

    void fill(int[][][] arr, int val) {
        for (int i = 0; i < arr.length; ++i) {
            fill(arr[i], val);
        }
    }

    int[][] newIntArray(int nx, int ny, int val) {
        int[][] res = new int[nx][ny];
        fill(res, val);
        return res;
    }

    int[][][] newIntArray(int nx, int ny, int nz, int val) {
        int[][][] res = new int[nx][ny][nz];
        fill(res, val);
        return res;
    }

    long[][] newLongArray(int nx, int ny, long val) {
        long[][] res = new long[nx][ny];
        for (int i = 0; i < nx; ++i) {
            Arrays.fill(res[i], val);
        }
        return res;
    }

    long[][][] newLongArray(int nx, int ny, int nz, long val) {
        long[][][] res = new long[nx][ny][nz];
        for (int i = 0; i < nx; ++i) {
            for (int j = 0; j < ny; ++j) {
                Arrays.fill(res[i][j], val);
            }
        }
        return res;
    }

    <T> ArrayList<T>[] newArrayListArray(int sz) {
        ArrayList<T>[] res = new ArrayList[sz];
        for (int i = 0; i < sz; ++i) {
            res[i] = new ArrayList<>();
        }
        return res;
    }

    String nextToken() throws IOException {
        while (strTok == null || !strTok.hasMoreTokens()) {
            String line = in.readLine();
            if (line == null) {
                return null;
            }
            strTok = new StringTokenizer(line);
        }
        return strTok.nextToken();
    }

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

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

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

    static StringTokenizer strTok;
    final static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
    final static PrintWriter out = new PrintWriter(System.out);
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.HashSet;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.io.IOException;
import java.util.ArrayList;
import java.io.InputStream;

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

    static class CInterestingGame {
        public void solve(int testNumber, InputReader s, PrintWriter w) {
            int n = s.nextInt();
            ArrayList<Pair>[] pair = new ArrayList[n + 1];
            for (int i = 1; i <= n; i++)
                pair[i] = new ArrayList<>();
            for (int k = 2; k <= n; k++)
                for (int a = 1; (long) (2 * a + k - 1) * k / 2 <= n; a++)
                    pair[(2 * a + k - 1) * k / 2].add(new Pair(a, k));
            int[] grundy = new int[n + 1];
            int[] val = new int[n + 1];
            Arrays.fill(val, Integer.MAX_VALUE);
            int[] pre = new int[n + 1];
            for (int i = 2; i <= n; i++) {
                HashSet<Integer> hs = new HashSet<>();
                for (Pair p : pair[i]) {
                    hs.add(pre[p.a + p.n - 1] ^ pre[p.a - 1]);
                    if ((pre[p.a + p.n - 1] ^ pre[p.a - 1]) == 0)
                        val[i] = Math.min(p.n, val[i]);
                }
                while (hs.contains(grundy[i]))
                    grundy[i]++;
                pre[i] = grundy[i] ^ pre[i - 1];
            }
            w.println(val[n] != Integer.MAX_VALUE ? val[n] : -1);
        }

        class Pair {
            int a;
            int n;

            Pair(int a, int n) {
                this.a = a;
                this.n = n;
            }

        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1024];
        private int curChar;
        private int numChars;
        private InputReader.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 nextInt() {
            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);

        }

    }
}


import java.util.Scanner;

public class PlayingWithSuperglue
{
	public static void main(String[] args)
	{

		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int m = sc.nextInt();
		int x1 = sc.nextInt();
		int y1 = sc.nextInt();
		int x2 = sc.nextInt();
		int y2 = sc.nextInt();
		int dx = Math.abs(x1-x2);
		int dy = Math.abs(y1 - y2);
		if(dx <= 4 && dy <= 4)
		{
			int min = Math.min(dx, dy);
			int max = Math.max(dx, dy);
			if(min < 3)
				System.out.println("First");
			else
			{
				if(min == 3 && max == 4)
					System.out.println("Second");
				else
					if(min == 3)
						System.out.println("First");
				if(min == 4)
					System.out.println("Second");
			}
		}
		else
			System.out.println("Second");
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class D
{
    public static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    public static StringTokenizer inp;
    public static void main(String[] args)  throws IOException
    {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        int ln[] = new int[1026];
        ln[0] = 0 ; ln[1023] = 2000000000;
        int ind = 1;
        for(int i = 2 ; i < 1024 ; i++)
        {
            char s[] = Integer.toBinaryString(i).toCharArray();
            for(int j = 1 ; j < s.length ; j++) s[j] = (s[j]=='0'?'4':'7');
            ln[ind++] = Integer.parseInt(String.valueOf(s).substring(1));
        }
        inp = new StringTokenizer(br.readLine());
        int pl = nextInt(),pr = nextInt() , vl=nextInt() , vr = nextInt() , k = nextInt();
        long ans = 0;
        int l = 1, r = k;
        for(; r <= 1022 ; r++,l++)
        {
            if(vl>ln[l])continue;
            if(ln[r] > pr || ln[l-1] > vr)break;
            ans+=(long)Math.max(0, (Math.min(ln[l], vr)- Math.max(vl, ln[l-1]+1) + 1))*Math.max(0, (Math.min(pr, ln[r+1]-1)- Math.max(ln[r], pl) + 1));
        }
        l=1;r=k;
        for(; r <= 1022 ; r++,l++)
        {
            if(pl>ln[l])continue;
            if(ln[r] > vr || ln[l-1] > pr)break;
            ans+=(long)Math.max(0, (Math.min(ln[l], pr)- Math.max(pl, ln[l-1]+1) + 1))*Math.max(0, (Math.min(vr, ln[r+1]-1)- Math.max(ln[r], vl) + 1));
        }
        if(k==1)
        {
            for(int i = 1; i <= 1022 ; i++)
                if(pl<=ln[i] && ln[i]<=pr && vl<=ln[i]&&ln[i]<=vr)ans--;
        }
        double res = (double)(ans)/((long)(pr-pl+1)*(vr-vl+1));
        System.out.printf("%.12f\n",Math.min(res, 1.0));
    }

    public static int nextInt(){return Integer.parseInt(inp.nextToken());}
    public static long nextLong(){return Long.parseLong(inp.nextToken());}
    public static double nextDouble(){return Double.parseDouble(inp.nextToken());}

}


//package af2017;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.util.InputMismatchException;

public class D {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	void solve()
	{
		int[] dual = {
				8, -1, -1, 3, 6, 9, 4, 7, 0, 5
		};
		char[] s = ns().toCharArray();
		for(int i = 0, j = s.length-1;i <= j;i++,j--){
			if(dual[s[i]-'0'] != s[j]-'0'){
				out.println("No");
				return;
			}
		}
		out.println("Yes");
	}

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

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

	public static void main(String[] args) throws Exception { new D().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 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[] na(int n)
	{
		int[] a = new int[n];
		for(int i = 0;i < n;i++)a[i] = ni();
		return a;
	}

	private int ni()
	{
		int num = 0, 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();
		}
	}

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

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


import java.io.*;
import java.util.*;
import java.util.regex.Pattern;

public class Solution implements Runnable {

	private StringTokenizer st;
	private BufferedReader in;
	private PrintWriter out;

	static class Profile {
		int[] ar;

		Profile(int[] ar) {
			this.ar = ar;
		}

		@Override
		public int hashCode() {
			final int prime = 31;
			int result = 1;
			result = prime * result + Arrays.hashCode(ar);
			return result;
		}

		@Override
		public boolean equals(Object obj) {
			if (this == obj)
				return true;
			if (obj == null)
				return false;
			if (getClass() != obj.getClass())
				return false;
			Profile other = (Profile) obj;
			if (!Arrays.equals(ar, other.ar))
				return false;
			return true;
		}
	}

	public void solve() throws IOException {
		long n = nextLong();
		int m = nextInt();
		char[] cs = new char[m];
		int[] ms = new int[m];
		int mul = 1;
		boolean[] need = new boolean[26];
		for (int i = 0; i < m; ++i) {
			cs[i] = next().charAt(0);
			ms[i] = nextInt();
			mul *= ms[i];
			need[cs[i] - 'A'] = true;
		}
		HashMap<Profile, Integer> map = new HashMap<Profile, Integer>();
		List<Profile> list = new ArrayList<Profile>();
		int[] counter = new int[m];
		for (int i = 0; i < mul; ++i) {
			Profile p = new Profile(counter.clone());
			list.add(p);
			map.put(p, map.size());
			for (int j = 0; j < m; ++j) {
				counter[j]++;
				if (counter[j] == ms[j]) {
					counter[j] = 0;
				} else {
					break;
				}
			}
		}
		int[][] mat = new int[mul][mul];
		for (int i = 0; i < mul; ++i) {
			for (char c = 'A'; c <= 'Z'; ++c) {
				if (!need[c - 'A']) {
					continue;
				}
				counter = list.get(i).ar.clone();
				for (int j = 0; j < m; ++j) {
					if (c == cs[j]) {
						counter[j] = (counter[j] + 1) % ms[j];
					}
				}
				mat[i][map.get(new Profile(counter))]++;
			}
		}
		mat = pow(mat, n);
		int ans = 0;
		loop: for (int i = 0; i < mul; ++i) {
			boolean[] ok = new boolean[26];
			counter = list.get(i).ar;
			for (int j = 0; j < m; ++j) {
				ok[cs[j] - 'A'] |= counter[j] == 0;
			}
			for (int j = 0; j < 26; ++j) {
				if (!ok[j] && need[j]) {
					continue loop;
				}
			}
			ans = (ans + mat[0][i]) % 12345;
		}
		out.println(ans);
	}

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

	private int[][] mul(int[][] a, int[][] b) {
		int[][] c = new int[a.length][a.length];
		for (int i = 0; i < a.length; ++i) {
			for (int j = 0; j < a.length; ++j) {
				long sum = 0;
				for (int t = 0; t < a.length; ++t) {
					sum += a[i][t] * b[t][j];
				}
				c[i][j] = (int)(sum % 12345);
			}
		}
		return c;
	}

	public void run() {
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			eat("");

			solve();

			out.close();
		} catch (Exception e) {
			e.printStackTrace();
			failed = true;
		}
	}

	void eat(String s) {
		st = new StringTokenizer(s);
	}

	String next() throws IOException {
		while (!st.hasMoreTokens()) {
			String line = in.readLine();
			if (line == null) {
				return null;
			}
			eat(line);
		}
		return st.nextToken();
	}

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

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

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

	static boolean failed = false;

	public static void main(String[] args) {
		Locale.setDefault(Locale.US);
		Thread th = new Thread(new Solution());
		th.start();
		try {
			th.join();
		} catch (InterruptedException iex) {
		}
		if (failed) {
			throw new RuntimeException();
		}
	}

}