import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.util.HashMap;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.util.Collections;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		FastScanner in = new FastScanner(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		int testCount = Integer.parseInt(in.next());
		for (int i = 1; i <= testCount; i++)
			solver.solve(i, in, out);
		out.close();
	}

	static class TaskE {
		final double eps = 1e-15;
		final long MAX_COORD = (int) 1e6;
		long MIN_X;
		long MIN_Y;
		long MAX_X;
		long MAX_Y;

		public void solve(int testNumber, FastScanner in, PrintWriter out) {
			int n = in.nextInt() - 1;
			long x0 = in.nextLong();
			long y0 = in.nextLong();
			MIN_X = -MAX_COORD - x0;
			MAX_X = +MAX_COORD - x0;
			MIN_Y = -MAX_COORD - y0;
			MAX_Y = +MAX_COORD - y0;
			PointLong[] p = new PointLong[n];
			for (int i = 0; i < n; i++) {
				long x = in.nextLong() - x0;
				long y = in.nextLong() - y0;
				p[i] = new PointLong(x, y);
			}
			Arrays.sort(p, (a, b) -> {
				boolean au = a.y > 0 || a.y == 0 && a.x > 0;
				boolean bu = b.y > 0 || b.y == 0 && b.x > 0;
				if (au != bu) {
					return au ? 1 : -1;
				}
				return -Long.signum(cross(a, b));
			});

			{
				int j = 0;
				for (int i = 0; i < n; i++) {
					j = Math.max(j, i + 1);
					while (cross(p[i], p[j % n]) > 0) {
						++j;
					}
					if (i != j % n && cross(p[i], p[j % n]) == 0) {
						out.println(0);
						return;
					}
					if (i != (i + 1) % n && cross(p[i], p[(i + 1) % n]) == 0) {
						out.println(0);
						return;
					}
				}
			}

			List<Line> lines = new ArrayList<>();
			{
				int j = 0;
				int best = -1;
				for (int i = 0; i < n; i++) {
					if (best >= 0 && cross(p[i], p[best]) <= 0) {
						best = -1;
					}
					if (i == j) {
						++j;
						if (j == n) j = 0;
					}
					while (cross(p[i], p[j]) > 0) {
						if (best < 0 || cross(p[best].sub(p[i]), p[j].sub(p[i])) > 0) {
							best = j;
						}
						++j;
						if (j == n) j = 0;
					}
					while (cross(p[i], p[j]) < 0) {
						--j;
						if (j < 0) j = n - 1;
					}
					if (best >= 0) {
						lines.add(new Line(p[i].toDoublePoint(), p[best].toDoublePoint()));
					}
				}
			}
			{
				int j = 0;
				for (int i = 0; i < n; i++) {
					++j;
					if (j == n) j = 0;
					if (cross(p[i], p[j]) > 0) {
						lines.add(new Line(p[i].toDoublePoint(), p[j].toDoublePoint()));
					}
				}
			}

//		List<Line> lines = new ArrayList<>();
//		for (int i = 0; i < n; i++) {
//			for (int j = 0; j < n; j++) {
//				if (cross(p[i], p[j]) > 0) {
//					lines.add(new Line(p[i].toDoublePoint(), p[j].toDoublePoint()));
//				}
//			}
//		}

			out.printf("%.15f\n", area(intersectSemiplanes(lines.toArray(new Line[0]))));
		}

		private double area(Point[] p) {
			if (p == null) {
				return 0;
			}
			double res = 0;
			for (int i = 0; i < p.length; i++) {
				int j = (i + 1) % p.length;
				res += (p[j].x - p[i].x) * (p[i].y + p[j].y);
			}
			return 0.5 * Math.abs(res);
		}

		private int compare(double a, double b) {
			if (Math.abs(a - b) < eps) {
				return 0;
			}
			return Double.compare(a, b);
		}

		private int sign(double x) {
			return compare(x, 0);
		}

		private double side(Point p, Line L) {
			return compare(p.x * L.a + p.y * L.b + L.c, 0);
		}

		private Point intersect(Line L1, Line L2) {
			double det = L1.a * L2.b - L2.a * L1.b;
			if (compare(det, 0) == 0) {
				return null;
			}
			double x = -(L1.c * L2.b - L2.c * L1.b) / det;
			double y = -(L1.a * L2.c - L2.a * L1.c) / det;
			return new Point(x, y);
		}

		private Point[] intersectSemiplanes(Line[] input) {
			List<Line> correctedInput = new ArrayList<>();
			for (Line L : input) {
				correctedInput.add(L);
			}
			Point[] corners = new Point[4];
			corners[0] = new Point(MIN_X, MIN_Y);
			corners[1] = new Point(MAX_X, MIN_Y);
			corners[2] = new Point(MAX_X, MAX_Y);
			corners[3] = new Point(MIN_X, MAX_Y);
			for (int i = 0; i < 4; i++) {
				correctedInput.add(new Line(corners[i], corners[(i + 1) % 4]));
			}

			Collections.sort(correctedInput, (L1, L2) -> {
				double ax = -L1.b, ay = L1.a;
				double bx = -L2.b, by = L2.a;
				boolean au = ay > 0 || (Math.abs(ay) < eps && ax > 0);
				boolean bu = by > 0 || (Math.abs(by) < eps && bx > 0);
				if (au != bu) {
					return au ? 1 : -1;
				}
				int s = -sign(ax * by - ay * bx);
				if (s != 0) {
					return s;
				}
				Point test = L1.anyPoint();
				return -sign(side(test, L2));
			});

			for (int i = correctedInput.size() - 1; i > 0; i--) {
				Line L1 = correctedInput.get(i);
				Line L2 = correctedInput.get(i - 1);
				double ax = -L1.b, ay = L1.a;
				double bx = -L2.b, by = L2.a;
				int d = sign(ax * bx + ay * by);
				int s = -sign(ax * by - ay * bx);
				if (d >= 0 && s == 0) {
					correctedInput.remove(i);
				}
			}

			Line[] borders = correctedInput.toArray(new Line[0]);
			List<Object> list = new ArrayList<>();
			list.add(borders[0]);
			list.add(intersect(borders[0], borders[1]));
			list.add(borders[1]);

			for (int i = 2; i < 2 * borders.length; i++) {
				Line L = borders[i % borders.length];
				while (list.size() >= 2) {
					Object o1 = list.get(list.size() - 2);
					Object o2 = list.get(list.size() - 1);
					if ((o1 instanceof Point) && (o2 instanceof Line)) {
						Point p = (Point) o1;
						if (side(p, L) > 0) {
							break;
						}
						list.remove(list.size() - 1);
						list.remove(list.size() - 1);
					} else {
						throw new AssertionError();
					}
				}
				Object obj = list.get(list.size() - 1);
				if (obj instanceof Line) {
					Line v = (Line) obj;
					if (sign(v.a * L.b - v.b * L.a) <= 0) {
						return null;
					}
					Point p = intersect(v, L);
					list.add(p);
					list.add(L);
				} else {
					throw new AssertionError();
				}
			}

			Map<Line, Integer> where = new HashMap<>();
			List<Line> allLines = new ArrayList<>();
			List<Point> res = new ArrayList<>();
			for (int i = 0; i < list.size(); i += 2) {
				Line L = (Line) list.get(i);
				allLines.add(L);
				if (where.containsKey(L)) {
					for (int j = where.get(L); j < allLines.size() - 1; j++) {
						res.add(intersect(allLines.get(j), allLines.get(j + 1)));
					}
					break;
				}
				where.put(L, i / 2);
			}
			return res.toArray(new Point[0]);
		}

		private long cross(PointLong a, PointLong b) {
			return a.x * b.y - a.y * b.x;
		}

		class Point {
			double x;
			double y;

			Point(double x, double y) {
				this.x = x;
				this.y = y;
			}

			public String toString() {
				return "(" + x + " " + y + ")";
				//return String.format("(%.4f %.4f)", x, y);
			}

		}

		class Line {
			double a;
			double b;
			double c;
			Point anyPoint;

			Line(double a, double b, double c) {
				this.a = a;
				this.b = b;
				this.c = c;
			}

			Line(Point p1, Point p2) {
				a = p1.y - p2.y;
				b = p2.x - p1.x;
				c = -a * p1.x - b * p1.y;
				double len = Math.sqrt(a * a + b * b);
				a /= len;
				b /= len;
				c /= len;
				anyPoint = p1;
			}

			Point anyPoint() {
				if (anyPoint != null) {
					return anyPoint;
				}
				if (Math.abs(b) < eps) {
					if (Math.abs(a) < eps) {
						throw new AssertionError();
					}
					return new Point(-c / a, 0);
				}
				return new Point(0, -c / b);
			}

			public String toString() {
				return a + " " + b + " " + c;
			}

		}

		class PointLong {
			long x;
			long y;

			PointLong(long x, long y) {
				this.x = x;
				this.y = y;
			}

			PointLong sub(PointLong o) {
				return new PointLong(x - o.x, y - o.y);
			}

			Point toDoublePoint() {
				return new Point(x, y);
			}

			public String toString() {
				return "(" + x + " " + y + ")";
			}

		}

	}

	static class FastScanner {
		private BufferedReader in;
		private StringTokenizer st;

		public FastScanner(InputStream stream) {
			in = new BufferedReader(new InputStreamReader(stream));
		}

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

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

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

	}
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.util.HashMap;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.util.Collections;
import java.io.InputStream;

/**
 * Built using CHelper plug-in
 * Actual solution is at the top
 */
public class Main {
	public static void main(String[] args) {
		InputStream inputStream = System.in;
		OutputStream outputStream = System.out;
		FastScanner in = new FastScanner(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskE solver = new TaskE();
		int testCount = Integer.parseInt(in.next());
		for (int i = 1; i <= testCount; i++)
			solver.solve(i, in, out);
		out.close();
	}

	static class TaskE {
		final double eps = 1e-12;
		final long MAX_COORD = (int) 1e6;
		long MIN_X;
		long MIN_Y;
		long MAX_X;
		long MAX_Y;

		public void solve(int testNumber, FastScanner in, PrintWriter out) {
			int n = in.nextInt() - 1;
			long x0 = in.nextLong();
			long y0 = in.nextLong();
			MIN_X = -MAX_COORD - x0;
			MAX_X = +MAX_COORD - x0;
			MIN_Y = -MAX_COORD - y0;
			MAX_Y = +MAX_COORD - y0;
			PointLong[] p = new PointLong[n];
			for (int i = 0; i < n; i++) {
				long x = in.nextLong() - x0;
				long y = in.nextLong() - y0;
				p[i] = new PointLong(x, y);
			}
			Arrays.sort(p, (a, b) -> {
				boolean au = a.y > 0 || a.y == 0 && a.x > 0;
				boolean bu = b.y > 0 || b.y == 0 && b.x > 0;
				if (au != bu) {
					return au ? 1 : -1;
				}
				return -Long.signum(cross(a, b));
			});

			{
				int j = 0;
				for (int i = 0; i < n; i++) {
					j = Math.max(j, i + 1);
					while (cross(p[i], p[j % n]) > 0) {
						++j;
					}
					if (i != j % n && cross(p[i], p[j % n]) == 0) {
						out.println(0);
						return;
					}
					if (i != (i + 1) % n && cross(p[i], p[(i + 1) % n]) == 0) {
						out.println(0);
						return;
					}
				}
			}

			List<Line> lines = new ArrayList<>();
			{
				int j = 0;
				int best = -1;
				for (int i = 0; i < n; i++) {
					if (best >= 0 && cross(p[i], p[best]) <= 0) {
						best = -1;
					}
					j = Math.max(j, i + 1);
					while (cross(p[i], p[j % n]) > 0) {
						if (best < 0 || cross(p[best].sub(p[i]), p[j % n].sub(p[i])) > 0) {
							best = j % n;
						}
						++j;
					}
					if (best >= 0) {
						lines.add(new Line(p[i].toDoublePoint(), p[best].toDoublePoint()));
					}
				}
			}
			{
				int j = 0;
				for (int i = 0; i < n; i++) {
					++j;
					if (j == n) j = 0;
					if (cross(p[i], p[j]) > 0) {
						lines.add(new Line(p[i].toDoublePoint(), p[j].toDoublePoint()));
					}
				}
			}

			out.printf("%.15f\n", area(intersectSemiplanes(lines.toArray(new Line[0]))));
		}

		private double area(Point[] p) {
			if (p == null) {
				return 0;
			}
			double res = 0;
			for (int i = 0; i < p.length; i++) {
				int j = i + 1;
				if (j == p.length) {
					j = 0;
				}
				res += (p[j].x - p[i].x) * (p[i].y + p[j].y);
			}
			return 0.5 * Math.abs(res);
		}

		private int compare(double a, double b) {
			if (Math.abs(a - b) < eps) {
				return 0;
			}
			return Double.compare(a, b);
		}

		private int sign(double x) {
			return compare(x, 0);
		}

		private double side(Point p, Line L) {
			return compare(p.x * L.a + p.y * L.b + L.c, 0);
		}

		private Point intersect(Line L1, Line L2) {
			double det = L1.a * L2.b - L2.a * L1.b;
			if (compare(det, 0) == 0) {
				return null;
			}
			double x = -(L1.c * L2.b - L2.c * L1.b) / det;
			double y = -(L1.a * L2.c - L2.a * L1.c) / det;
			return new Point(x, y);
		}

		private Point[] intersectSemiplanes(Line[] input) {
			List<Line> correctedInput = new ArrayList<>();
			for (Line L : input) {
				correctedInput.add(L);
			}
			Point[] corners = new Point[4];
			corners[0] = new Point(MIN_X, MIN_Y);
			corners[1] = new Point(MAX_X, MIN_Y);
			corners[2] = new Point(MAX_X, MAX_Y);
			corners[3] = new Point(MIN_X, MAX_Y);
			for (int i = 0; i < 4; i++) {
				correctedInput.add(new Line(corners[i], corners[(i + 1) % 4]));
			}

			Collections.sort(correctedInput, (L1, L2) -> {
				double ax = -L1.b, ay = L1.a;
				double bx = -L2.b, by = L2.a;
				boolean au = ay > 0 || (ay == 0 && ax > 0);
				boolean bu = by > 0 || (by == 0 && bx > 0);
				if (au != bu) {
					return au ? 1 : -1;
				}
				int s = -sign(ax * by - ay * bx);
				if (s != 0) {
					return s;
				}
				return -sign(side(L1.p1, L2));
			});

			{
				boolean[] dead = new boolean[correctedInput.size()];
				for (int i = correctedInput.size() - 1; i > 0; i--) {
					Line L1 = correctedInput.get(i);
					Line L2 = correctedInput.get(i - 1);
					double ax = -L1.b, ay = L1.a;
					double bx = -L2.b, by = L2.a;
					int d = sign(ax * bx + ay * by);
					int s = -sign(ax * by - ay * bx);
					if (d >= 0 && s == 0) {
						dead[i] = true;
					}
				}
				List<Line> list = new ArrayList<>();
				for (int i = 0; i < correctedInput.size(); i++) {
					if (!dead[i]) {
						list.add(correctedInput.get(i));
					}
				}
				correctedInput = list;
			}

			Line[] borders = correctedInput.toArray(new Line[0]);
			List<Object> list = new ArrayList<>();
			list.add(borders[0]);
			list.add(intersect(borders[0], borders[1]));
			list.add(borders[1]);

			for (int i = 2; i < 2 * borders.length; i++) {
				Line L = borders[i % borders.length];
				while (list.size() >= 2) {
					Object o1 = list.get(list.size() - 2);
					Object o2 = list.get(list.size() - 1);
					if ((o1 instanceof Point) && (o2 instanceof Line)) {
						Point p = (Point) o1;
						if (side(p, L) > 0) {
							break;
						}
						list.remove(list.size() - 1);
						list.remove(list.size() - 1);
					} else {
						throw new AssertionError();
					}
				}
				Object obj = list.get(list.size() - 1);
				if (obj instanceof Line) {
					Line v = (Line) obj;
					if (sign(v.a * L.b - v.b * L.a) <= 0) {
						return null;
					}
					Point p = intersect(v, L);
					list.add(p);
					list.add(L);
				} else {
					throw new AssertionError();
				}
			}

			Map<Line, Integer> where = new HashMap<>();
			List<Line> allLines = new ArrayList<>();
			List<Point> res = new ArrayList<>();
			for (int i = 0; i < list.size(); i += 2) {
				Line L = (Line) list.get(i);
				allLines.add(L);
				if (where.containsKey(L)) {
					for (int j = where.get(L); j + 1 < allLines.size(); j++) {
						res.add(intersect(allLines.get(j), allLines.get(j + 1)));
					}
					break;
				}
				where.put(L, i / 2);
			}
			return res.toArray(new Point[0]);
		}

		private long cross(PointLong a, PointLong b) {
			return a.x * b.y - a.y * b.x;
		}

		class Point {
			double x;
			double y;

			Point(double x, double y) {
				this.x = x;
				this.y = y;
			}

			public String toString() {
				return String.format("(%.4f %.4f)", x, y);
			}

		}

		class Line {
			double a;
			double b;
			double c;
			Point p1;
			Point p2;

			Line(Point p1, Point p2) {
				this.p1 = p1;
				this.p2 = p2;
				a = p1.y - p2.y;
				b = p2.x - p1.x;
				c = -a * p1.x - b * p1.y;
				// double len = Math.sqrt(a * a + b * b);
				// a /= len;
				// b /= len;
				// c /= len;
			}

			public String toString() {
				return a + " " + b + " " + c;
			}

		}

		class PointLong {
			long x;
			long y;

			PointLong(long x, long y) {
				this.x = x;
				this.y = y;
			}

			PointLong sub(PointLong o) {
				return new PointLong(x - o.x, y - o.y);
			}

			Point toDoublePoint() {
				return new Point(x, y);
			}

			public String toString() {
				return "(" + x + " " + y + ")";
			}

		}

	}

	static class FastScanner {
		private BufferedReader in;
		private StringTokenizer st;

		public FastScanner(InputStream stream) {
			in = new BufferedReader(new InputStreamReader(stream));
		}

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

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

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

	}
}


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

public class Main {
    static boolean find = false;
    static HashSet<String> set = new HashSet<>();
    public static void main(String[] args) throws Exception {
        PrintWriter out = new PrintWriter(System.out,true);
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        int n = Integer.parseInt(in.readLine());
        String[] mas = new String[n];
        StringTokenizer st = new StringTokenizer(in.readLine());
        for(int i = 0;i < n;i++) mas[i] = st.nextToken();
        func(mas,n-1);
        if(find) {
            out.println("YES");
        }else{
            out.println("NO");
        }
    }

    public static void func(String[] mas, int last) {
        String d = Arrays.toString(mas)+last;
        if(set.contains(d)) return;
        set.add(d);
        if(last == 0 || find) find = true;
        if(last > 0 && (mas[last-1].charAt(0) == mas[last].charAt(0) || mas[last-1].charAt(1) == mas[last].charAt(1))) {
            String a = mas[last-1];
            mas[last-1] = mas[last];
            func(mas,last-1);
            mas[last-1] = a;
        }
        if(last > 2 && (mas[last-3].charAt(0) == mas[last].charAt(0) || mas[last-3].charAt(1) == mas[last].charAt(1))) {
            String a = mas[last-3];
            mas[last-3] = mas[last];
            func(mas,last-1);
            mas[last-3] = a;
        }
    }
}


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

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

public class  Main  {

	//ArrayList<Integer> lis = new ArrayList<Integer>();
	//ArrayList<String> lis = new ArrayList<String>();
	//ArrayList<test> lis = new ArrayList<test>();
//	static long sum=0;
//	static boolean f=false;
	//static String s[],r="";
//	static int dx[]={1,-1,0,0,1,1,-1,-1};
  //  static int dy[]={0,0,1,-1,1,-1,1,-1},n,m,w=0;
	//static int dp[][][][],co,r=0;
	//throws IOException
	//static char c[][];
	static boolean b=false,me[][][][][];

public  static void main(String[] args)  {
   //googlein.txt C-small-attempt0.in
//	Scanner sc =new Scanner(new File("file.txt"));
	 Scanner sc =new Scanner(System.in);
	  //File file = new File("file.txt");
	//	PrintWriter pw = new PrintWriter(new BufferedWriter(new FileWriter(file)));
	//	sc.useDelimiter("(\\s)+|[,]");

	  while(sc.hasNext()){
		   //long sum=0;
	//	  int n=sc.nextInt(),m=sc.nextInt(),k=sc.nextInt();
		int   n=sc.nextInt();
		b=false;
	//	db((int)sc.next().charAt(0));
      char  c[][]=new char[2][n];
	 me=new boolean [2][100][100][100][n];
		 for(int i=0;i<n;i++){
			 String s=sc.next();
			 c[0][i]=s.charAt(0);
			 c[1][i]=s.charAt(1);
		 }

		 if( n==1 ){ System.out.println("YES");return;}

		 rep(n-1,c);

	  System.out.println(b? "YES":"NO");

		 }

}
	// db("Case #"+(k)+": "+c);
	 //	pw.println("Case #"+(k)+": "+c);

	 	//pw.flush();
	 	//pw.close();

   static void rep(int a,char p[][]){

	   if( b )return;
	   if(a==0){ b=true; return; }
	  // db(p[0],p[1]);

	   if(3<a && me[0][p[0][a-2]][p[0][a-1]][p[0][a]][a] && me[1][p[1][a-2]][p[1][a-1]][p[1][a]][a] )return;

	   if(  p[0][a]==p[0][a-1]   ||  p[1][a]==p[1][a-1]   ){
	   char np[][]=new char[2][a];
	   for(int i=0;i<a;i++){np[0][i]=p[0][i]; np[1][i]=p[1][i];}  np[0][a-1]=p[0][a];np[1][a-1]=p[1][a];
	     rep(a-1,np ); }

	   if(  0<=a-3 && (  p[0][a]==p[0][a-3]  || p[1][a]==p[1][a-3] ) ){
	   char np[][]=new char[2][a];
	   for(int i=0;i<a;i++){np[0][i]=p[0][i]; np[1][i]=p[1][i];}  np[0][a-3]=p[0][a];np[1][a-3]=p[1][a];
	     rep(a-1,np ); }

	 if(3<a)  me[1][p[1][a-2]][p[1][a-1]][p[1][a]][a] = me[1][p[1][a-2]][p[1][a-1]][p[1][a]][a]=true;

   }

    static void db(Object... os){
	         System.err.println(Arrays.deepToString(os));

	}

}

/*class P implements Comparable<P>{
    int v,vv,t;
	P(int v,int vv,int t){
		this.v=v;
	    this.vv=vv;
	    this.t=t;
	}
	  public int compareTo(P x){
          return t-x.t;
	   }

}*/


import java.util.HashSet;
import java.util.Scanner;

public class Main {

    /**
     * @param args
     */
    static int n;
    static StringBuilder[] strs;
    static HashSet<String> hs=new HashSet<String>();
    static boolean ok(int x,int y)
    {
        return strs[x].charAt(0)==strs[y].charAt(0)
                || strs[x].charAt(1)==strs[y].charAt(1);
    }

    static boolean dfs(int x){
        if(x==0)return true;
        if(x>1){
            if(hs.contains(strs[x].append(strs[x-1]).append(strs[x-2]).append(x)))return false;
            if(x>2&&ok(x,x-3)){
                StringBuilder t=strs[x-3];
                strs[x-3]=strs[x];
                if(dfs(x-1))return true;
                strs[x-3]=t;
            }
        }
        if(ok(x,x-1)){
            StringBuilder t=strs[x-1];
            strs[x-1]=strs[x];
            if(dfs(x-1))return true;
            strs[x-1]=t;
        }
        if(x>1)hs.add(strs[x].append(strs[x-1]).append(strs[x-2]).append(x).toString());
        return false;
    }
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        Scanner in = new Scanner(System.in);
        n=in.nextInt();strs=new StringBuilder[n];
        for(int i=0;i<n;i++)strs[i]=new StringBuilder(in.next());
        System.out.println(dfs(n-1)?"YES":"NO");
    }

}


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

public class R130_D2_B {

    public static void main(String[] args) throws Exception {
        InputReader in = new InputReader(System.in);
        int n = in.readInt();
        q = new String[n];
        for (int i = 0; i < n; i++) {
            q[i] = in.readString();
        }

        if(n==1){
        System.out.println("YES");
        return;
        }
        String val1 = q[n-1];
        String val2 = q[n-2];
        if (val1.charAt(0) == val2.charAt(0)
                    || val1.charAt(1) == val2.charAt(1)){
                    System.out.println("YES");
                    }else
                    System.out.println("NO");

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1000];
        private int curChar, numChars;

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

        private 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 long readLong() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            long 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 String readString() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            StringBuffer res = new StringBuffer();
            do {
                res.appendCodePoint(c);
                c = read();
            } while (!isSpaceChar(c));
            return res.toString();
        }

        private boolean isSpaceChar(int c) {
            return c == ' ' || c == '\n' || c == '\r' || c == '\t' || c == -1;
        }

        private String readLine0() {
            StringBuffer buf = new StringBuffer();
            int c = read();
            while (c != '\n' && c != -1) {
                buf.appendCodePoint(c);
                c = read();
            }
            return buf.toString();
        }

        public String readLine() {
            String s = readLine0();
            while (s.trim().length() == 0)
                s = readLine0();
            return s;
        }

        public String readLine(boolean ignoreEmptyLines) {
            if (ignoreEmptyLines)
                return readLine();
            else
                return readLine0();
        }

        public char readCharacter() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            return (char) c;
        }

        public double readDouble() {
            int c = read();
            while (isSpaceChar(c))
                c = read();
            int sgn = 1;
            if (c == '-') {
                sgn = -1;
                c = read();
            }
            double res = 0;
            while (!isSpaceChar(c) && c != '.') {
                if (c == 'e' || c == 'E')
                    return res * Math.pow(10, readInt());
                if (c < '0' || c > '9')
                    throw new InputMismatchException();
                res *= 10;
                res += c - '0';
                c = read();
            }
            if (c == '.') {
                c = read();
                double m = 1;
                while (!isSpaceChar(c)) {
                    if (c == 'e' || c == 'E')
                        return res * Math.pow(10, readInt());
                    if (c < '0' || c > '9')
                        throw new InputMismatchException();
                    m /= 10;
                    res += (c - '0') * m;
                    c = read();
                }
            }
            return res * sgn;
        }
    }
}


import java.util.Scanner;

/**
 *
 * @author sina
 */
public class ACMC1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Scanner in=new Scanner(System.in);
       int n=in.nextInt();
       int[] x=new int[4*n+1];
       int[] y=new int[4*n+1];
       int maxX=0;
       int maxY=0;
       int maxOX=0;
       int maxOY=0;
       for (int i = 0; i < 4*n+1; i++) {
            x[i]=in.nextInt();
            y[i]=in.nextInt();
            if(x[i]!=y[i])
            {
                if(maxOX<x[i]){
                    if(x[i]>=maxX)
                    {
                        maxOX=maxX;
                        maxX=x[i];
                    }
                    else
                    {
                        maxOX=x[i];
                    }
                }

                if(maxOY<y[i]){
                    if(y[i]>=maxY)
                    {
                        maxOY=maxY;
                        maxY=y[i];
                    }
                    else
                    {
                        maxOY=y[i];
                    }
                }
            }
       }
           int l=Math.min(maxOX, maxOY);
       for (int i = 0; i < 4*n+1; i++) {
            if(x[i]!=l&&y[i]!=l&&x[i]!=0&&y[i]!=0)
            {
                System.out.println(x[i]+" "+y[i]);
                break;
            }
            else if(x[i]>l||y[i]>l)
            {
                System.out.println(x[i]+" "+y[i]);
                break;
            }
        }
    }

}


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

public class C1_1184 {

	public static int solve (int [] countx,int n)
	{
		int i = 0;
		while (countx[i] == 0)
			i++;
		if (countx[i] != n + 1) {
			return i;
		}
		i++;
		int k = i;
		for (; i < k + n - 1; i++) {
			if (countx[i] != n) {
				return i;
			}
		}
		if (countx[i] != n + 1) {
			return i;
		}
		i++;
		while (countx[i] == 0) {
			i++;
		}
		return i;
	}
	public static void main(String[] args) throws IOException {
		Scanner sc = new Scanner(System.in);
		PrintWriter pw = new PrintWriter(System.out);
		int n = sc.nextInt();
		int[] countx = new int[51];
		int[] county = new int[51];
		for (int i = 0; i < 4 * n + 1; i++) {
			countx[sc.nextInt()]++;
			county[sc.nextInt()]++;
		}
		pw.println(solve(countx, n)+" "+solve(county, n));
		pw.flush();
		pw.close();
	}

	static class Scanner {
		StringTokenizer st;
		BufferedReader br;

		public Scanner(InputStream s) {
			br = new BufferedReader(new InputStreamReader(s));
		}

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

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

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

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

		public double nextDouble() throws IOException {
			String x = next();
			StringBuilder sb = new StringBuilder("0");
			double res = 0, f = 1;
			boolean dec = false, neg = false;
			int start = 0;
			if (x.charAt(0) == '-') {
				neg = true;
				start++;
			}
			for (int i = start; i < x.length(); i++)
				if (x.charAt(i) == '.') {
					res = Long.parseLong(sb.toString());
					sb = new StringBuilder("0");
					dec = true;
				} else {
					sb.append(x.charAt(i));
					if (dec)
						f *= 10;
				}
			res += Long.parseLong(sb.toString()) / f;
			return res * (neg ? -1 : 1);
		}

		public boolean ready() throws IOException {
			return br.ready();
		}

	}

}


import java.util.*;
import java.io.*;
import java.math.BigInteger;
public class template {
	public static void main(String[] args) throws Exception {
		FastScanner sc = new FastScanner();
		PrintWriter pw = new PrintWriter(System.out);
		int n =sc.nextInt();
		int[] o = new int[4*n+1];
		int[] p= new int[4*n+1];
		int[] r= new int[51];
		int[] d= new int[51];
		for(int i=0;i<4*n+1;i++) {
			int x=  sc.nextInt();
			int y= sc.nextInt();
			o[i]=x;
			p[i]=y;
			r[x]++;
			d[y]++;
		}
		int sx =-1;
		int ex =-1;
		int sy =-1;
		int ey =-1;
		for(int i=0;i<r.length;i++) {
			if(r[i]>=n+1) {
				if(sx==-1) {
					sx=i;
				}
				else ex =i;
			}
			if(d[i]>=n+1) {
				if(sy==-1) {
					sy=i;
				}
				else ey =i;
			}
		}
		boolean[][] x = new boolean[51][51];
		for(int i=sx;i<=ex;i++) {
			x[i][sy]=true;
			x[i][ey]=true;
		}
		for(int i=sy;i<=ey;i++) {
			x[sx][i]=true;
			x[ex][i]=true;
		}
		for(int i=0;i<4*n+1;i++) {
			if(!x[o[i]][p[i]]) {
				pw.println(o[i]+" "+p[i]);
				break;
			}
		}
		pw.close();
	}
}
@SuppressWarnings("all")
class FastScanner {
    BufferedReader br;
    StringTokenizer st;
    public FastScanner(BufferedReader d) {
        br=d;
    }
    public FastScanner(String s) {
        try {
            br = new BufferedReader(new FileReader(s));
        } catch (FileNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

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

    String nextToken() {
        while (st == null || !st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (IOException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }

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

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

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


/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package acmc1;

import java.util.Scanner;

/**
 *
 * @author sina
 */
public class ACMC1 {

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
       Scanner in=new Scanner(System.in);
       int n=in.nextInt();
       int[] x=new int[4*n+1];
       int[] y=new int[4*n+1];
       int maxX=0;
       int maxY=0;
       int maxOX=0;
       int maxOY=0;
       for (int i = 0; i < 4*n+1; i++) {
            x[i]=in.nextInt();
            y[i]=in.nextInt();
            if(x[i]!=y[i])
            {
                if(x[i]>=maxX)
                {
                    maxOX=maxX;
                    maxX=x[i];
                }
                if(y[i]>=maxY)
                {
                    maxOY=maxY;
                    maxY=y[i];
                }
            }
       }
       int l=Math.min(maxOX, maxOY);
       for (int i = 0; i < 4*n+1; i++) {
            if(x[i]!=l&&y[i]!=l&&x[i]!=0&&y[i]!=0)
            {
                System.out.println(x[i]+" "+y[i]);
                break;
            }
            else if(x[i]>l||y[i]>l)
            {
                System.out.println(x[i]+" "+y[i]);
                break;
            }
        }
    }

}


import java.util.Scanner;
public class Main{
    class MaximApartment {
        private int[] result; //Holds the number of good apartments for each combination
        private final boolean debug = false; //Debug Mode

        public void debugPrintln(String s){
            if(debug) System.out.println(s);
        }
        public void debugPrint(String s){
            if(debug) System.out.print(s);
        }
        //Takes and returns the input argument
        public int[] getInput(){
            int[] result = {-1, -1};
            boolean stop = false;
            Scanner s = new Scanner(System.in);
            int val1 = -1;
            int val2 = -1;
            debugPrintln("Please provide the number of apartments followed by a space followed by the number of good apartments");
            String input = s.nextLine();
            String[] inputVal = input.split(" ");
            if(inputVal.length == 2){
                val1 = Integer.parseInt(inputVal[0]);
                val2 = Integer.parseInt(inputVal[1]);
                if(((val1 > 0 && val1 <= 1000000000)) && (val2 >= 0 && val2 <= val1)){
                    result[0] = val1;
                    result[1] = val2;
                    stop = true;
                }
            }

            return result;
        }

        public void runA(){
            int[] inputs = getInput();

            if(inputs[0] != -1 && inputs[1] != -1){
                int min = Math.min(1, Math.min(inputs[1], inputs[0] - inputs[1]));

                int max = 0;
                int emptyApartments = inputs[0] - inputs[1];
                if(emptyApartments < (2 * inputs[1])) max = emptyApartments;
                else max = 2 * inputs[1];
                System.out.println(min + " " + max);

            }
            else{
                System.out.println("0 0");
                debugPrintln("ERROR: Input Parameters that were returned does not contain valid value: " + inputs[0] + " and " + inputs[1]);
            }

        }

    }
    public static void main(String[] args){
        MaximApartment ma = new MaximApartment();
        ma.runA();
    }
}


import java.util.*;
public class Main{
    public static void main(String[] args){
      Scanner s= new Scanner(System.in);
      int n = s.nextInt();
      int k = s.nextInt();
      System.out.print(k&&n-k?1:0+" "+n>=3*k?2*k:n-k);
    }
}


import java.util.Scanner;

/**
 * Created by tarekihya on 06/09/2017.
 */
public class others {

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

        long maison = in.nextLong();
        long full = in.nextLong();
if(maison==full||full==0){
    System.out.println(0+" "+0);
}else{

        System.out.println(1+" "+maison-full);
    }
    }
}


public class Second {
    public static void main(String[] args){
        Scanner sc = new Scanner(System.in);
        long n = sc.nextLong();
        long k = sc.nextLong();
        long min = 1;
        long ways = n/2;
        if(k==n){
            System.out.println(0+" "+0);
        }
        else if(k==1){
            System.out.println(1+" "+2);
        }
        else if(k==ways){
            System.out.println(1+" "+ways);
        }
        else{
            ways = n-k;
            System.out.println(1+" "+ways);
        }
    }
}


import java.util.*;

public class CF336D {

    static final int mod = (int)Math.pow(10, 9) + 7;

    public static void main(String[] args) {

        Scanner in = new Scanner(System.in);
        int n = in.nextInt();
        int m = in.nextInt();
        int g = in.nextInt();

        long[] fact = new long[n + m + 1];
        long[] inv = new long[Math.max(n, m) + 1];
        fact[0] = 1;
        inv[0] = 1;
        for (int k = 1; k <= n + m; k++)
        {
            fact[k] = k * fact[k - 1] % mod;
            if (k <= Math.max(n,m))
                inv[k] = power(fact[k], mod - 2) % mod;
        }

        if (m == 0)
        {
            if (g % 2 != n % 2)
                System.out.println(1);
            else
                System.out.println(0);
        }
        else
        {
            long total = 0;
            for (int k = 1; k <= n + 1; k++)
                if ((g % 2 != k % 2 && (m != 1 || m == 1 && k != n + 1)) || (g % 2 == (n + 1) % 2 && m == 1 && k == n + 1))
                    total = (total + (fact[n + m - k] * inv[m - 1] % mod) * inv[n - k + 1]) % mod;
            System.out.println(total);
        }
    }

    public static long power(long a, int n)
    {
       if (n == 0)
            return 1;
        else if (n == 1)
            return a % mod;
        else if (n % 2 == 0)
            return power(a*a % mod, n/2) % mod;
        else
            return (a * (power(a*a % mod, (n-1)/2) % mod)) % mod;
    }
}


//package cf195;

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

public class D {
	FastScanner in;
	PrintWriter out;

	long[] fact;
	final long mod = (long) (1e9 + 7);

	public void solve() throws IOException {
		int n = in.nextInt();
		int m = in.nextInt();
		int g = in.nextInt();
		fact = new long[n + m + 1];
		fact[0] = 1;
		for (int i = 1; i <= n + m; i++) {
			fact[i] = (fact[i - 1] * i) % mod ;
		}
		System.out.println(getAns(n, m, g));
	}

	public long getAns(int n, int m, int req) {
		if (n == 0) {
			if (m == 0) {
				if (req == 0) {
					return 0;
				} else {
					return 1;
				}

			}
			if (m == 1) {
				if (req == 1) {
					return 1;
				} else {
					return 0;
				}
			}

			if (m > 1) {
				if (req == 0) {
					return 1;
				} else {
					return 0;
				}
			}
		}
 		if (req == 0) {
			long ans = getAns(n - 1, m, 1);
			if (m > 0) {
				ans = (ans + cnk(n + m - 1, m - 1)) % mod;
			}
			return ans;
		} else {
			return getAns(n - 1, m, 0);
		}
	}

	public long cnk(int n, int k) {
		return (((fact[n] * inverse(fact[k])) % mod) * inverse(fact[n - k])) % mod;
	}

	public long inverse(long x) {
		return power(x, mod - 2, mod);
	}

	public long power(long x, long pow, long mod) {
		if (pow == 0) {
			return 1;
		}
		if ((pow % 2) == 0) {
			return power(((x * x) % mod), pow / 2, mod);
		} else {
			return (power(x, pow - 1, mod) * x) % mod;
		}
	}

	public void run() {
		try {
			in = new FastScanner(System.in);
			out = new PrintWriter(System.out);

			solve();

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

	class FastScanner {
		BufferedReader br;
		StringTokenizer st;

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

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

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

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

	public static void main(String[] arg) {
		new D().run();
	}
}


import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.util.*;
import java.awt.Point;

public class CodeForces {
    static boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null;

    Map<Long, Long> mem = new HashMap<Long, Long>();
    Map<Point, Long> memc = new HashMap<Point, Long>();

    private static final long MOD = 1000000007;

    long pw(long x, long y) {
        long res = 1;
        while (y > 0) {
            if ((y % 2) > 0) {
                --y;
                res = (res * x) % MOD;
            } else {
                y /= 2;
                x = (x * x) % MOD;
            }
        }
        return res;
    }

    long rev(long x)
    {
        return pw(x, MOD - 2);
    }

    void runCase(int caseNum) throws IOException {
        long m = nextLong();
        long n = nextLong();
        int g = nextInt();

        if (n == 0) {
            if ((m & 1) == 1) {
                if (g == 0)
                    System.out.println("1");
                else
                    System.out.println("0");
            } else {
                if (g == 0)
                    System.out.println("0");
                else
                    System.out.println("1");
            }
            return;
        }

        long prevZero = 1;
        long prevOne = 0;
        if (n == 1) {
            prevOne = 1;
            prevZero = 0;
        }
        long pc = 1;

        for (int i = 1; i <= m; ++i) {
            pc *= n + i - 1;
            if (pc >= MOD)
                pc %= MOD;
            pc *= rev(i);
            if (pc >= MOD)
                pc %= MOD;
            long one = prevZero;
            long zero = prevOne;
            zero += pc;
            if (zero >= MOD)
                zero %= MOD;
            prevOne = one;
            prevZero = zero;
        }

//        long res = go(n, m, g);
//        System.out.println(res);
        if (g == 1)
            System.out.println(prevOne);
        else
            System.out.println(prevZero);
    }

    public static void main(String[] args) throws IOException {
        if (ONLINE_JUDGE){
            System.out.println();
            in = new BufferedReader(new InputStreamReader(System.in));
            out = new PrintWriter(System.out);
        }else{
            in = new BufferedReader(new FileReader("input.txt"));
            out = new PrintWriter(System.out);
            //out = new PrintWriter("output.txt");
        }
        new CodeForces().runIt();
        out.flush();
        out.close();
        return;
    }

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

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

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

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

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

    void runIt() throws IOException {
        st = new StringTokenizer("");

//        int N = nextInt();
//        for (int i = 0; i < N; i++) {
//            runCase(i + 1);
//        }
        runCase(0);
        out.flush();
    }

}


import java.io.BufferedReader;
import java.io.FileNotFoundException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashSet;
import java.util.PriorityQueue;
import java.util.StringTokenizer;
import java.util.TreeSet;

/**
 *
 *
 * 3 2 3 5
 * -2 -1 4 -1 2 7 3
 *
 *
 * @author pttrung
 */
public class D {

    public static long MOD = 1000000007;
    public static long[] dp;

    public static void main(String[] args) throws FileNotFoundException {
        PrintWriter out;
        Scanner in = new Scanner();
        //out = new PrintWriter(new FileOutputStream(new File("output.txt")));
        out = new PrintWriter(System.out);
        int m = in.nextInt();
        int n = in.nextInt();
        int g = in.nextInt();

        if (n + m == 1) {
            if (g == 0) {
                out.println(m);
            } else {
                out.println(n);
            }
        } else {
            dp = new long[n + m + 1];
            dp[0] = 1;
            dp[1] = 1;
            for (int i = 1; i < dp.length; i++) {
                dp[i] = i * dp[i - 1];
                dp[i] %= MOD;
            }
            out.println(cal(n, m, g));
        }
        out.close();
    }

    public static long cal(int n, int m, int need) {
        long result = 0;
        while (true) {

            if (n + m == 1) {
                if (need == 0) {
                    result += m;
                } else {
                    result += n;
                }
                break;
            }

            if (need == 0) {
                if (n > 0) {
                    int a = n - 1;
                    int pos = a + m;
                    BigInteger x = BigInteger.valueOf(dp[pos]);
                    x = x.multiply(BigInteger.valueOf(dp[a]).multiply(BigInteger.valueOf(dp[m])).modInverse(BigInteger.valueOf(MOD))).mod(BigInteger.valueOf(MOD));
                    result += x.longValue();
                }
                if (m > 0) {
                    m--;
                    need = 1;
                }
            } else {
                if (m > 0) {
                    m--;
                    need = 0;
                }
            }
        }
        return result;
    }

    public static boolean nextPer(int[] data) {
        int i = data.length - 1;
        while (i > 0 && data[i] < data[i - 1]) {
            i--;
        }
        if (i == 0) {
            return false;
        }
        int j = data.length - 1;
        while (data[j] < data[i - 1]) {
            j--;
        }
        int temp = data[i - 1];
        data[i - 1] = data[j];
        data[j] = temp;
        Arrays.sort(data, i, data.length);
        return true;
    }

    public static int digit(long n) {
        int result = 0;
        while (n > 0) {
            n /= 10;
            result++;
        }
        return result;
    }

    public static double dist(long a, long b, long x, long y) {
        double val = (b - a) * (b - a) + (x - y) * (x - y);
        val = Math.sqrt(val);
        double other = x * x + a * a;
        other = Math.sqrt(other);
        return val + other;

    }

    public static class Point implements Comparable<Point> {

        int x, y;

        public Point(int start, int end) {
            this.x = start;
            this.y = end;
        }

        @Override
        public int hashCode() {
            int hash = 5;
            hash = 47 * hash + this.x;
            hash = 47 * hash + this.y;
            return hash;
        }

        @Override
        public boolean equals(Object obj) {
            if (obj == null) {
                return false;
            }
            if (getClass() != obj.getClass()) {
                return false;
            }
            final Point other = (Point) obj;
            if (this.x != other.x) {
                return false;
            }
            if (this.y != other.y) {
                return false;
            }
            return true;
        }

        @Override
        public int compareTo(Point o) {
            return x - o.x;
        }
    }

    public static class FT {

        int[] data;

        FT(int n) {
            data = new int[n];
        }

        public void update(int index, int value) {
            while (index < data.length) {
                data[index] += value;
                index += (index & (-index));
            }
        }

        public int get(int index) {
            int result = 0;
            while (index > 0) {
                result += data[index];
                index -= (index & (-index));
            }
            return result;

        }
    }

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

    public static long pow(long a, long b) {
        if (b == 0) {
            return 1;
        }
        if (b == 1) {
            return a;
        }
        long val = pow(a, b / 2);
        if (b % 2 == 0) {
            return val * val % MOD;
        } else {
            return val * (val * a % MOD) % MOD;

        }
    }

    static class Scanner {

        BufferedReader br;
        StringTokenizer st;

        public Scanner() throws FileNotFoundException {
            // System.setOut(new PrintStream(new BufferedOutputStream(System.out), true));
            br = new BufferedReader(new InputStreamReader(System.in));
            //br = new BufferedReader(new InputStreamReader(new FileInputStream(new File("input.txt"))));
        }

        public String next() {

            while (st == null || !st.hasMoreTokens()) {
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (Exception e) {
                    throw new RuntimeException();
                }
            }
            return st.nextToken();
        }

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

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

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

        public String nextLine() {
            st = null;
            try {
                return br.readLine();
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }

        public boolean endLine() {
            try {
                String next = br.readLine();
                while (next != null && next.trim().isEmpty()) {
                    next = br.readLine();
                }
                if (next == null) {
                    return true;
                }
                st = new StringTokenizer(next);
                return st.hasMoreTokens();
            } catch (Exception e) {
                throw new RuntimeException();
            }
        }
    }
}


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.InputMismatchException;

/**
 * @author Nikita Gorokhov <wackloner@yandex-team.ru>
 */
public class E {

    private void solve() {
        int n = nextInt();
        String s = next();

        int[] col = new int[28];
        col[0] = Integer.MAX_VALUE;
        for (int i = 1; i < n; i++) {
            col[i] = Integer.MIN_VALUE;
        }

        int totalMax = 0;
        int[] p = new int[n];
        for (int i = 0; i < n; i++) {
            int a = s.charAt(i) - 'a';
            int max = 0;
            for (int j = 1; j <= Math.min(n, 27); j++) {
                if (col[j - 1] > a && a >= col[j]) {
                    col[j] = a;
                    max = j;
                }
            }
            p[i] = max - 1;
            totalMax = Math.max(totalMax, max);
        }
        if (totalMax > 2) {
            out.println("NO");
        } else {
            out.println("YES");
            for (int i = 0; i < n; i++) {
                out.print(p[i]);
            }
            out.println();
        }
    }

    private final static String INPUT_FILENAME = "input.txt";
    private final static boolean ONLINE_JUDGE = System.getProperty("ONLINE_JUDGE") != null;

    private InputStream inputStream;
    private PrintWriter out;

    private void run() throws FileNotFoundException {
        inputStream = ONLINE_JUDGE ? System.in : new FileInputStream(INPUT_FILENAME);
        out = new PrintWriter(System.out);

        int t = 1;

        for (int testNum = 0; testNum < t; testNum++) {
            solve();
        }

        out.flush();
    }

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

    private byte[] buffer = new byte[1024];
    private int bufferLen = 0, bufferPtr = 0;

    private int readByte() {
        if (bufferLen == -1) {
            throw new InputMismatchException();
        }
        if (bufferPtr >= bufferLen) {
            bufferPtr = 0;
            try {
                bufferLen = inputStream.read(buffer);
            } catch (IOException e) {
                throw new InputMismatchException();
            }
            if (bufferLen <= 0) {
                return -1;
            }
        }
        return buffer[bufferPtr++];
    }

    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 nextDouble() {
        return Double.parseDouble(next());
    }

    private char nextChar() {
        return (char) skip();
    }

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

    private int nextInt() {
        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 nextLong() {
        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();
        }
    }
}


import java.io.*;
import java.util.*;
import java.util.StringTokenizer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Scanner;
import java.util.StringTokenizer;
public class Main
{
  //your static variables go here:

  static ArrayList<Integer> graph[];
  static boolean vis[];
  static int seive[]=new int[1000001];
  static int dis[]=new int[1000001];
  static int subtree[]=new int[1000001];

  static int time=0;
  //******************************************************************
  static class FastReader
  {
      BufferedReader br;
      StringTokenizer st;
      public FastReader()
      { br = new BufferedReader(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 nextLine(){ String str = "";
      try{str = br.readLine();}
      catch (IOException e) {e.printStackTrace();}
      return str;}
    }
//*************************************************************************
/**

*/
//left right is for query range
public static void build(int a[], long seg[], int start, int end, int cur)
{
  if(start>end)
  return;
  if(start==end)
  {
    seg[cur]=seive[a[start]];
    return;
  }
  int mid=start+(end-start)/2;
  build(a, seg, start, mid, 2*cur+1);
  build(a,seg, mid+1, end, 2*cur+2);
  seg[cur]=seg[2*cur+1]+seg[2*cur+2];
}
public static long query( int left, int right, int start, int end, int cur, long seg[] )
{
  if(start>end)
  return 0;
  if(left>end||right<start)
    return 0;
  if(left<=start&&right>=end)
    return seg[cur];
  int mid=start+(end-start)/2;
  return query(left,right,start, mid, 2*cur+1, seg)+query( left, right, mid+1, end, 2*cur+2, seg);
}

public static void update( int left, int right, int start, int end, int cur, long seg[], long value)
{
  if(start>end)
    return;
  if(left>end||right<start)
    return;
  if(start==end)
  {
    //a[start]=value*value;
    seg[cur]=value;
    return;
  }
  int mid=start+(end-start)/2;
   update(left,right,start, mid, 2*cur+1, seg, value);update( left, right, mid+1, end, 2*cur+2, seg, value);
   seg[cur]=(seg[cur*2+1]+seg[cur*2+2]);
}
public static void fill_seive()
{
  seive[0]=1;
  seive[1]=1;
  for( int i=2;i<1000001;i++)
  {
    if(seive[i]==0)
    {
      seive[i]=i;
      for( int j=i;j<1000001;j+=i)
      {
        if(seive[j]==0)
        {
          seive[j]=i;
        }
      }
    }
  }

}
//
/*
take a vertex and start with the discovering time from the root
now for range query and point update the following works
can also think of the solution using the euler tour
*/
public static void eulerlist(int u)
{
  vis[u]=true;
  dis[u]=time;
  time++;
  for( int i=0;i<graph[u].size();i++)
  {
    int v=graph[u].get(i);
    if(!vis[v])
    {
      eulerlist(v);
      subtree[u]+=subtree[v];
    }
  }
}
public static void main(String[] args)
{
    FastReader sc=new FastReader();
    StringBuilder sb=new StringBuilder();
      int n=sc.nextInt();
      String str=sc.next();
      char s[]=str.toCharArray();
      int a[]=new int[26];
      int sup[]=new int[30];
      ArrayList<Integer> ans=new ArrayList<>();
      HashSet<Integer> hs[]=new HashSet[26];
      for( int i=0;i<26;i++)
      hs[i]=new HashSet<>();
      int max=Integer.MIN_VALUE;
      for( int i=0;i<n;i++)
      {
        int check=-1;
        for( int k=1;k<=26;k++)
        {
          boolean ch1=true;
          for( int j=s[i]-'a'+1;j<26;j++)
          {
            if(hs[j].contains(k))
            {
              ch1=false;
              break;
            }
          }
          if(ch1==true)
          {
            check=k;break;
          }
        }
        ans.add(check);
        hs[s[i]-'a'].add(check);
        max=Math.max(max,check);
      }
      if(max>2)
      {
        System.out.println("NO");
      }
      else
      for( int i=0;i<n;i++)
      {
        ans.get(i)--;
        sb.append(ans.get(i));
        sb.append(" ");
      }
      System.out.println(sb.toString());
}
}

class Pair
{
  int f,s;
  Pair( int f, int s)
  {
    this.f=f;
    this.s=s;
  }
}


// package com.company;
import java.util.*;
import java.lang.*;
import java.io.*;
//****Use Integer Wrapper Class for Arrays.sort()****
public class BQ5 {
    public static void main(String[] Args){
        FastReader scan=new FastReader();
        int n=scan.nextInt();
        String s=scan.next();
        int[] ds=new int[26];
        int[] col=new int[n];
        for(int i=n-1;i>=0;i--){
            char ch=s.charAt(i);
            int ac=ch-'a';
            int max=0;
            for(int j=0;j<ac;j++){
                max=Math.max(max,ds[j]);
            }
            ds[ac]=max+1;
            col[i]=max+1;
        }
        int ans=Integer.MIN_VALUE;
        for(int i=0;i<n;i++){
            ans=Math.max(col[i],ans);
        }
//        System.out.println(ans);
//        StringBuilder print=new StringBuilder();
//        for(int i=0;i<n;i++){
//            print.append(col[i]+" ");
//        }
        if(ans<=2){
            System.out.println("YES");
            for(int i=0;i<n;i++){
                System.out.print((col[i]-1));
            }
            System.out.println();
        }
        else{
            System.out.println("NO");
        }
    }
    static class FastReader {
        BufferedReader br;
        StringTokenizer st;

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

}


import java.io.*;
import java.util.*;
public class Solution
{
    static ArrayList<Integer> adj[];
    static boolean visited[];
    static int N;
    static int color[];
    public static void main(String ag[])
    {
        Scanner sc=new Scanner(System.in);
        int i,j,k;

        int N=sc.nextInt();
        char A[]=sc.next().toCharArray();

        visited=new boolean[N];
        color=new int[N];
        adj=new ArrayList[N];
        for(i=0;i<N;i++)
        adj[i]=new ArrayList<>();

        for(i=0;i<N;i++)
        {
            for(j=0;j<i;j++)
            {
                if(A[j]>A[i])
                {
                    adj[j].add(i);
                    adj[i].add(j);
                }
            }
        }

        boolean flag=true;
        for(i=0;i<N;i++)
        {
            if(!visited[i]&&adj[i].size()>0)
            {
                flag=BFS(i);
                if(!flag)
                break;
            }
        }
        if(!flag)
        System.out.println("NO");
        else
        {
            StringBuilder sb=new StringBuilder();
            System.out.println("YES");
            for(i=0;i<N;i++)
            sb.append(color[i]);
            System.out.println(sb);
        }
    }
    public static boolean BFS(int node)
    {
        Queue<Integer> q=new LinkedList<>();
        q.add(node);
        color[node]=1;
        while(!q.isEmpty())
        {
            int curr=q.poll();
            visited[curr]=true;
            Iterator<Integer> itr=adj[curr].iterator();
            while(itr.hasNext())
            {
                int next=itr.next();
                if(!visited[next])
                {
                    color[next]=1-color[curr];
                    q.add(next);
                }
                else
                {
                    if(color[next]==color[curr])
                    return false;
                }
            }
        }
        return true;
    }

}


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

/* Name of the class has to be "Main" only if the class is public. */

public class Main
{

    static PrintWriter out;

	static class FastReader{
		BufferedReader br;
		StringTokenizer st;
		public FastReader(){
			br=new BufferedReader(new InputStreamReader(System.in));
			out=new PrintWriter(System.out);
		}
		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;
		}
	}

// SHIVAM GUPTA :

// ASCII = 48 + i ;

// SHIVAM GUPTA :

public static int  min(int a ,int b , int c, int d)
{

       int[] arr = new int[4] ;
       arr[0] = a;
       arr[1] = b ;
       arr[2] = c;
       arr[3] = d;
       Arrays.sort(arr) ;

       return arr[0];

}

public static int  max(int a ,int b , int c, int d)
{

       int[] arr = new int[4] ;
       arr[0] = a;
       arr[1] = b ;
       arr[2] = c;
       arr[3] = d;
       Arrays.sort(arr) ;

       return arr[3];

}

static int sieve =  1000000 ;

static boolean[] prime =  new boolean[sieve + 1] ;

public static void sieveOfEratosthenes()
    {
        // TRUE == prime

        // FALSE ==  COMPOSITE

        // FALSE== 1

        for(int i=0;i< sieve + 1;i++)
            prime[i] = true;

        for(int p = 2; p*p <= sieve; p++)
        {

            if(prime[p] == true)
            {

                for(int i = p*p; i <= sieve; i += p)
                    prime[i] = false;
            }
        }

    }

public static String reverse(String input)
{
    String op = "" ;

    for(int i = 0; i < input.length() ; i++ )
    {
        op = input.charAt(i)+  op ;
    }

return op ;
}

public static int[] sortI(int[] arr)
{
      Arrays.sort(arr) ;
      return arr ;
}

public static int[] sortD(int[] arr)
{
      Arrays.sort(arr) ;

      int i =0 ; int j = arr.length -1  ;

      while( i < j)
      {
            int temp = arr[i] ;
            arr[i] =arr[j] ;
            arr[j] = temp ;
            i++ ; j-- ;
      }

      return arr ;
}

public static boolean isPossibleTriangle(int a  ,int b , int c)
{
      if( a + b > c && c+b > a && a +c > b)
      {
            return true  ;
      }

      return false  ;

}

public static int gcd(int a, int b )
{

if(b==0)return a ;

else return gcd(b,a%b) ;

}

public static int lcm(int a, int b ,int c , int d )
{

int temp = lcm(a,b , c) ;

 int ans = lcm(temp ,d ) ;

return ans  ;

}

public static int lcm(int a, int b ,int c )
{

int temp = lcm(a,b) ;

int ans =  lcm(temp ,c) ;

return ans  ;

}

public static int lcm(int a , int b )
{

int gc = gcd(a,b);

return (a*b)/gc ;

}

    public static int countDigit(long n)
    {
        return (int)Math.floor(Math.log10(n) + 1);
    }

   static final int MAXN = 100001;

    static int spf[] = new int[MAXN];

    static void sieve()
    {
        spf[1] = 1;
        for (int i=2; i<MAXN; i++)

            spf[i] = i;

        for (int i=4; i<MAXN; i+=2)
            spf[i] = 2;

        for (int i=3; i*i<MAXN; i++)
        {

            if (spf[i] == i)
            {

                for (int j=i*i; j<MAXN; j+=i)

                    if (spf[j]==j)
                        spf[j] = i;
            }
        }
    }

// The above code works well for n upto the order of 10^7.
// Beyond this we will face memory issues.

// Time Complexity: The precomputation for smallest prime factor is done in O(n log log n)
// using sieve.
// Where as in the calculation step we are dividing the number every time by
// the smallest prime number till it becomes 1.
// So, let’s consider a worst case in which every time the SPF is 2 .
// Therefore will have log n division steps.

// Hence, We can say that our Time Complexity will be O(log n) in worst case.

    static Vector<Integer> getFactorization(int x)
    {
        Vector<Integer> ret = new Vector<>();
        while (x != 1)
        {
            ret.add(spf[x]);
            x = x / spf[x];
        }
        return ret;
    }

public static void main (String[] args) throws java.lang.Exception
{
  FastReader scn = new FastReader() ;

int x1 = scn.nextInt() ; int y1 = scn.nextInt() ;
int x2 = scn.nextInt() ; int y2 = scn.nextInt() ;
int x3 = scn.nextInt() ; int y3 = scn.nextInt() ;

out.println(3) ;
out.println(x1+x2-x3 +" " + y1+y2-y3) ;
out.println(x3+x2-x1 +" " + y3+y2-y1) ;
out.println(x1+x3-x2 +" " + y1+y3-y2) ;

out.flush() ;

}

}


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

public class parallelogram {
	public static void main(String [] args) throws IOException{
		BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		System.out.println(3);
		int[][] points = new int[2][3];
		for(int i=0; i<3; i++) {
			st = new StringTokenizer(f.readLine());
			points[0][i]=Integer.parseInt(st.nextToken());
			points[1][i]=Integer.parseInt(st.nextToken());
		}
		Set answers = new HashSet<String>();
		int xdiff1 = points[0][1]-points[0][2];
		int xdiff2 = points[0][0]-points[0][1];
		int ydiff1 = points[1][1]-points[1][2];
		int ydiff2 = points[1][0]-points[1][1];
		answers.add((points[0][0]+xdiff1)+" "+points[1][0]+ydiff1);
		answers.add((points[0][0]-xdiff1)+" "+points[1][0]-ydiff1);
		answers.add((points[0][2]+xdiff2)+" "+points[1][2]+ydiff2);
		answers.add((points[0][2]-xdiff2)+" "+points[1][2]-ydiff2);
		for(String str : answers) {
			System.out.println(str);
		}
	}

}


/* package codechef; // don't place package name! */

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

/* Name of the class has to be "Main" only if the class is public. */
public class Point{
    int x,y;
    public Point(int x,int y){
        this.x=x;
        this.y=y;
    }
}
public class Codechef
{
	public static void main (String[] args) throws java.lang.Exception
	{
		// your code goes here
		Scanner in = new Scanner(System.in);
		Point a=new Point(in.nextInt(),in.nextInt());
		Point b=new Point(in.nextInt(),in.nextInt());
		Point c=new Point(in.nextInt(),in.nextInt());
		System.out.println(3);
		System.out.println((b.x-c.x+a.x)+" "+(b.y-c.y+a.y));
		System.out.println((c.x-a.x+b.x)+" "+(c.y-a.y+b.y));
		System.out.println((a.x-b.x+c.x)+" "+(a.y-b.y+c.y));
	}
}


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

public class bachgold {
	public static void main(String [] args) throws IOException{
		BufferedReader f = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st;
		System.out.println(3);
		int[][] points = new int[2][3];
		for(int i=0; i<3; i++) {
			st = new StringTokenizer(f.readLine());
			points[0][i]=Integer.parseInt(st.nextToken());
			points[1][i]=Integer.parseInt(st.nextToken());
		}
		Set answers = new HashSet<String>();
		int xdiff1 = points[0][1]-points[0][2];
		int xdiff2 = points[0][0]-points[0][1];
		int ydiff1 = points[1][1]-points[1][2];
		int ydiff2 = points[1][0]-points[1][1];
		answers.add((points[0][0]+xdiff1)+" "+(points[1][0]+ydiff1));
		answers.add((points[0][0]-xdiff1)+" "+(points[1][0]-ydiff1));
		answers.add((points[0][2]+xdiff2)+" "+(points[1][2]+ydiff2));
		answers.add((points[0][2]-xdiff2)+" "+(points[1][2]-ydiff2));
		for(String str : answers) {
			System.out.println(str);
		}
	}

}


//package com.company;

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

public class Main {
    public static class Task {

        public class Maxflow {
            class Edge {
                int t, rev;
                long cap, f;
                public Edge(int t, int rev, long cap) {
                    this.t = t;
                    this.rev = rev;
                    this.cap = cap;
                }
            }
            public Maxflow(int n) {
                graph = new List[n];
                for (int i = 0; i < n; i++) {
                    graph[i] = new ArrayList<>();
                }
            }
            List<Edge>[] graph;
            void addEdge(int s, int t, long cap) {
                graph[s].add(new Edge(t, graph[t].size(), cap));
                graph[t].add(new Edge(s, graph[s].size() - 1, 0));
//                if (cap != Integer.MAX_VALUE)
//                System.err.println(s + " " + t + " " + cap);
            }

            boolean dinicBFS(int src, int dest, int[] dist) {
                Arrays.fill(dist, -1);
                dist[src] = 0;
                int[] Q = new int[graph.length];
                int sizeQ = 0;
                Q[sizeQ++] = src;
                for (int i = 0; i < sizeQ; i++) {
                    int u = Q[i];
                    for (Edge e: graph[u]) {
                        if (dist[e.t] < 0 && e.f < e.cap) {
                            dist[e.t] = dist[u] + 1;
                            Q[sizeQ++] = e.t;
                        }
                    }
                }
                return dist[dest] >= 0;
            }

            long dinicDFS(int[] ptr, int[] dist, int dest, int u, long f) {
                if (u == dest) return f;
                for (;ptr[u] < graph[u].size(); ++ptr[u]) {
                    Edge e =  graph[u].get(ptr[u]);
                    if (dist[e.t] == dist[u] + 1 && e.f < e.cap) {
                        long df = dinicDFS(ptr, dist, dest, e.t, Math.min(f, e.cap - e.f));
                        if (df > 0) {
                            e.f += df;
                            graph[e.t].get(e.rev).f -= df;
                            return df;
                        }
                    }
                }
                return 0;
            }

            long maxFLow(int src, int dest) {
                long flow = 0;
                int[] dist = new int[graph.length];
                while (dinicBFS(src, dest, dist)) {
                    int[] ptr = new int[graph.length];
                    while (true) {
                        long df = dinicDFS(ptr, dist, dest, src, Long.MAX_VALUE);
                        if (df == 0) break;
                        flow += df;
                    }
                }
                return flow;
            }
        }

        int interValIndex;
        public class IntervalNode {
            int l, r;
            IntervalNode left, right;
            int index;
            public IntervalNode(int L, int R) {
                this.l = L;
                this.r = R;
                this.index = interValIndex++;
                int mid = (l + r) / 2;
                if (mid > l) {
                    left = new IntervalNode(l, mid);
                    right = new IntervalNode(mid, r);
                }
            }
        }
        int mfEnd;
        IntervalNode[] baseNodes;
        public void dfsAddEdge(Maxflow mf, IntervalNode node) {
            if (node.left != null) {
                mf.addEdge(node.index, node.left.index, Integer.MAX_VALUE / 2);
                mf.addEdge(node.index, node.right.index, Integer.MAX_VALUE / 2);
                dfsAddEdge(mf, node.left);
                dfsAddEdge(mf, node.right);
            } else {
                baseNodes[node.l] = node;
                mf.addEdge(node.index, mfEnd, 1);
            }
        }

        public void searchCover(Maxflow mf, IntervalNode node, int l, int r, int start) {
            if (l <= node.l && node.r <= r) {
                mf.addEdge(start, node.index, 1);
                return;
            }
            if (node.l >= r || node.r <= l) return;
            searchCover(mf, node.left, l, r, start);
            searchCover(mf, node.right, l, r, start);
        }

        public int dfsDecode(List<Maxflow.Edge>[] graph, int u) {
            for (Maxflow.Edge e: graph[u]) {
                if (e.f > 0) {
                    if (e.t == mfEnd) {
                        e.f -= 1;
                        return u;
                    }
                    int ret = dfsDecode(graph, e.t);
                    if (ret > 0) {
                        e.f -= 1;
                        return ret;
                    }
                }
            }
            return -1;
        }

        public void solve(Scanner sc, PrintWriter pw) throws IOException {
            int n = sc.nextInt();
            int m = sc.nextInt();
            interValIndex = n + 1;
            IntervalNode root = new IntervalNode(0, m);
            mfEnd = interValIndex;
            Maxflow mf = new Maxflow(mfEnd + 1);
            baseNodes = new IntervalNode[m];
            dfsAddEdge(mf, root);
            int[][] weapons = new int[n][];
            for (int i = 0; i < n; i++) {
                int type = sc.nextInt();
                if (type == 0) {
                    int k = sc.nextInt();
                    weapons[i] = new int[k + 1];
                    weapons[i][0] = type;
                    for (int j = 1; j <= k; j++) {
                        weapons[i][j] = sc.nextInt() - 1;
                    }
                    mf.addEdge(0, i + 1, 1);
                    for (int j = 1; j <= k; j++) {
                        mf.addEdge(i + 1, baseNodes[weapons[i][j]].index, 1);
                    }
                } else if (type == 1) {
                    int l = sc.nextInt() - 1;
                    int r = sc.nextInt();
                    weapons[i] = new int[3];
                    weapons[i][0] = type;
                    weapons[i][1] = l;
                    weapons[i][2] = r;
                    mf.addEdge(0, i + 1, 1);
                    searchCover(mf, root, l, r, 1 + i);
                } else if (type == 2) {
                    int a = sc.nextInt() - 1;
                    int b = sc.nextInt() - 1;
                    int c = sc.nextInt() - 1;
                    weapons[i] = new int[4];
                    weapons[i][0] = type;
                    weapons[i][1] = a;
                    weapons[i][2] = b;
                    weapons[i][2] = c;
                    mf.addEdge(0, i + 1, 2);
                    mf.addEdge(i + 1, baseNodes[a].index, 1);
                    mf.addEdge(i + 1, baseNodes[b].index, 1);
                    mf.addEdge(i + 1, baseNodes[c].index, 1);
                }
            }
            long flow = mf.maxFLow(0, mfEnd);
            pw.println(flow);
            List<Maxflow.Edge>[] graph = mf.graph;
            Map<Integer, Integer> toIndex = new HashMap<>();
            for (int i = 0; i < baseNodes.length; i++) {
                toIndex.put(baseNodes[i].index, i);
            }
            toIndex.put(-1, -1);
            int[][] connectTo = new int[n][2];
            for (int i = 0; i < n; i++) {
                connectTo[i][1] = -1;
                connectTo[i][0] = toIndex.get(dfsDecode(graph, i + 1));
                if (weapons[i][0] == 2) connectTo[i][1] = toIndex.get(dfsDecode(graph, i + 1));
            }
            int[] whose = new int[m];
            for (int i = 0; i < n; i++) {
                if (weapons[i][0] != 2 && connectTo[i][0] != -1) {
                    whose[connectTo[i][0]] = i;
                }
            }
            for (int i = 0; i < n; i++) {
                if (weapons[i][0] == 2 && connectTo[i][1] == -1 && connectTo[i][0] != -1) {
                    for (int j = 1; j < 4; j++) {
                        if (connectTo[i][0] != weapons[i][j]) {
                            connectTo[i][1] = weapons[i][j];
                            connectTo[whose[weapons[i][j]]][0] = -1;
                            break;
                        }
                    }
                }
            }
            for (int i = 0; i < n; i++) {
                if (connectTo[i][0] >= 0) {
                    pw.println((i + 1) + " " + (connectTo[i][0] + 1));
                }
                if (connectTo[i][1] >= 0) {
                    pw.println((i + 1) + " " + (connectTo[i][1] + 1));
                }
            }
        }
    }

    static long TIME_START, TIME_END;

    public static void main(String[] args) throws IOException {
        Scanner sc = new Scanner(System.in);
//        Scanner sc = new Scanner(new FileInputStream("input"));
        PrintWriter pw = new PrintWriter(new BufferedOutputStream(System.out));
//        PrintWriter pw = new PrintWriter(new FileOutputStream("output"));

        Runtime runtime = Runtime.getRuntime();
        long usedMemoryBefore = runtime.totalMemory() - runtime.freeMemory();
        TIME_START = System.currentTimeMillis();
        Task t = new Task();
        t.solve(sc, pw);
        TIME_END = System.currentTimeMillis();
        long usedMemoryAfter = runtime.totalMemory() - runtime.freeMemory();
        pw.close();
        System.err.println("Memory increased: " + (usedMemoryAfter - usedMemoryBefore) / 1000000);
        System.err.println("Time used: " + (TIME_END - TIME_START) + ".");
    }

    static class Scanner {
        StringTokenizer st;
        BufferedReader br;

        public Scanner(InputStream s) {
            br = new BufferedReader(new InputStreamReader(s));
        }

        public Scanner(FileReader s) throws FileNotFoundException {
            br = new BufferedReader(s);
        }

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

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

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

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

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

        public boolean ready() throws IOException {
            return br.ready();
        }
    }
}


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

public class A implements Runnable{
	public static void main (String[] args) {new Thread(null, new A(), "_cf", 1 << 28).start();}

	int ptr, append[];

	public void run() {
		FastScanner fs = new FastScanner();
		PrintWriter out = new PrintWriter(System.out);
		System.err.println("Go!");

		append = new int[1000]; ptr = 0;
		int n = fs.nextInt();
		int m = fs.nextInt();
		MaxFlowDinic mfd = new MaxFlowDinic();
		ST st = new ST(m);
		int nodes = 2 + n + st.n;
		ArrayList<Edge>[] graph = mfd.createGraph(nodes);
		int src = n + st.n, snk = src+1;

		int[][] data = new int[n][];
		for(int i = 0; i < n; i++) {
			int type = fs.nextInt();
			if(type == 0) { //list of k people they can hit
				int k = fs.nextInt();
				data[i] = new int[k+1];
				data[i][0] = type;
				for(int j = 1; j < data[i].length; j++) {
					data[i][j] = fs.nextInt()-1;
					mfd.addEdge(graph, i, n + st.loc[data[i][j]], 1);
				}
				mfd.addEdge(graph, src, i, 1);

			}
			else if(type == 1) { //range of [l, r] people they can hit
				data[i] = new int[3];
				data[i][0] = type;
				data[i][1] = fs.nextInt()-1;
				data[i][2] = fs.nextInt()-1;

				mfd.addEdge(graph, src, i, 1);

				ptr = 0;
				st.find(1, data[i][1], data[i][2]);
				for(int j = 0; j < ptr; j++) {
					mfd.addEdge(graph, i, n + append[j], 1);
				}
			}
			else { //can hit exactly 0/2 people.
				data[i] = new int[4];
				data[i][0] = type;
				for(int j = 1; j < 4; j++) {
					data[i][j] = fs.nextInt()-1;
					mfd.addEdge(graph, i, n + st.loc[data[i][j]], 1);
				}
				mfd.addEdge(graph, src, i, 2);
			}
		}

		int oo = (int)1e4;
		for(int i = 1; i < st.n; i++) {
			if(st.left[i] == -1) continue;
			if(st.left[i] == st.right[i]) {
				mfd.addEdge(graph, n + i, snk, 1);
			}
			else {
				mfd.addEdge(graph, n+i, n+st.left(i), oo);
				mfd.addEdge(graph, n+i, n+st.right(i), oo);
			}
		}

		int flow = mfd.maxFlow(graph, src, snk);
		out.println(flow);
		boolean[] hit = new boolean[m];
		for(int i = 1; i < st.n; i++) {
			if(st.left[i] == st.right[i] && st.left[i] != -1) {
				for(Edge e : graph[n + i]) if(e.t == snk && e.f > 0) {
					hit[ st.left[i] ] = true;
					break;
				}
			}
		}
		int[] id = new int[m]; Arrays.fill(id, -1);
		int[] gets = new int[3];
		for(int i = 0; i < n; i++) if(data[i][0] == 2) {
			int got = 0;
			ptr = 0; gets[0] = gets[1] = gets[2] = -1;
			for(Edge e : graph[i]) if(e.t != src) {
				if(e.f > 0) {
					got++;
					int it = e.t - n;
					id[st.left[it]] = i+1;
				}
				else if(hit[st.left[e.t-n]]) {
					gets[ptr++] = e.t;
				}
			}
			if(got == 1) {
				id[ st.left[gets[0] - n] ] = i+1;
			}
		}
		for(int i = 0; i < n; i++) if(data[i][0] == 0) {
			for(Edge e : graph[i]) if(e.t != src && e.f>0) {
				if(id[st.left[e.t-n]] == -1)
					id[st.left[e.t-n]] = i+1;
				break;
			}
		}
		for(int i = 0; i < n; i++) if(data[i][0] == 1) {
			int at = i;
			while(true) {
				int someone = -1;
				for(Edge e : graph[at]) if(e.f>0) {
					e.f--;
					at = e.t;
					someone = at;
					break;
				}
				if(someone == -1) break;
				if(at >= n && st.left[at-n] == st.right[at-n]) {
					if(id[st.left[at-n]] == -1) {
						id[st.left[at-n]] = i+1;
					}
					break;
				}
			}
		}
		for(int i = 0; i < m; i++) if(id[i] != -1) {
			out.printf("%d %d\n", id[i], i+1);
		}
		out.close();
	}

	class ST {
		int[] left, right;
		int[] loc;
		int n, nn;
		ST(int a) {
			nn = a;
			n = 4*a+100;
			left = new int[n];
			right = new int[n];
			Arrays.fill(left, -1); Arrays.fill(right, -1);
			loc = new int[nn];
			init(1, 0, a-1);
		}
		int left(int p) { return p << 1; }
		int right(int p) { return (p << 1)+1; }
		void init(int p, int ll, int rr) {
			left[p] = ll; right[p] = rr;
			if(ll == rr) {
				loc[ll] = p;
				return;
			}
			int mid = (ll + rr) / 2;
			init(left(p), ll, mid);
			init(right(p), mid+1, rr);
		}
		void find(int p, int ll, int rr) {
			if(rr < left[p] || ll > right[p]) return;
//			System.out.printf("Finding on %d [%d, %d] Looking for (%d, %d)\n", p, left[p], right[p], ll, rr);
			if(ll <= left[p] && right[p] <= rr) {
//				System.out.println(" Back");
				append[ptr++] = p;
				return;
			}
			if(left[p] == right[p]) return;
			find(left(p), ll, rr);
			find(right(p), ll, rr);
		}
	}

	class Edge {
		int t, rev, cap, f;
		public Edge(int t, int rev, int cap) {
			this.t = t;
			this.rev = rev;
			this.cap = cap;
		}
	}

	class MaxFlowDinic {
		ArrayList<Edge>[] createGraph(int nodes) {
			ArrayList<Edge>[] graph = new ArrayList[nodes];
			for (int i = 0; i < nodes; i++)
				graph[i] = new ArrayList<>();
			return graph;
		}

		void addEdge(List<Edge>[] graph, int s, int t, int cap) {
			graph[s].add(new Edge(t, graph[t].size(), cap));
			graph[t].add(new Edge(s, graph[s].size() - 1, 0));
		}

		boolean dinicBfs(List<Edge>[] graph, int src, int dest, int[] dist) {
			Arrays.fill(dist, -1);
			dist[src] = 0;
			int[] Q = new int[graph.length];
			int sizeQ = 0;
			Q[sizeQ++] = src;
			for (int i = 0; i < sizeQ; i++) {
				int u = Q[i];
				for (Edge e : graph[u]) {
					if (dist[e.t] < 0 && e.f < e.cap) {
						dist[e.t] = dist[u] + 1;
						Q[sizeQ++] = e.t;
					}
				}
			}
			return dist[dest] >= 0;
		}

		int dinicDfs(List<Edge>[] graph, int[] ptr, int[] dist, int dest, int u, int f) {
			if (u == dest)
				return f;
			for (; ptr[u] < graph[u].size(); ++ptr[u]) {
				Edge e = graph[u].get(ptr[u]);
				if (dist[e.t] == dist[u] + 1 && e.f < e.cap) {
					int df = dinicDfs(graph, ptr, dist, dest, e.t, Math.min(f, e.cap - e.f));
					if (df > 0) {
						e.f += df;
						graph[e.t].get(e.rev).f -= df;
						return df;
					}
				}
			}
			return 0;
		}

		int maxFlow(List<Edge>[] graph, int src, int dest) {
			int flow = 0;
			int[] dist = new int[graph.length];
			while (dinicBfs(graph, src, dest, dist)) {
				int[] ptr = new int[graph.length];
				while (true) {
					int df = dinicDfs(graph, ptr, dist, dest, src, Integer.MAX_VALUE);
					if (df == 0)
						break;
					flow += df;
				}
			}
			return flow;
		}
	}

	class FastScanner {
		public int BS = 1<<16;
		public char NC = (char)0;
		byte[] buf = new byte[BS];
		int bId = 0, size = 0;
		char c = NC;
		double num = 1;
		BufferedInputStream in;

		public FastScanner() {
			in = new BufferedInputStream(System.in, BS);
		}

		public FastScanner(String s) throws FileNotFoundException {
			in = new BufferedInputStream(new FileInputStream(new File(s)), BS);
		}

		public char nextChar(){
			while(bId==size) {
				try {
					size = in.read(buf);
				}catch(Exception e) {
					return NC;
				}
				if(size==-1)return NC;
				bId=0;
			}
			return (char)buf[bId++];
		}

		public int nextInt() {
			return (int)nextLong();
		}

		public long nextLong() {
			num=1;
			boolean neg = false;
			if(c==NC)c=nextChar();
			for(;(c<'0' || c>'9'); c = nextChar()) {
				if(c=='-')neg=true;
			}
			long res = 0;
			for(; c>='0' && c <='9'; c=nextChar()) {
				res = (res<<3)+(res<<1)+c-'0';
				num*=10;
			}
			return neg?-res:res;
		}

		public double nextDouble() {
			double cur = nextLong();
			return c!='.' ? cur:cur+nextLong()/num;
		}

		public String next() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c>32) {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public String nextLine() {
			StringBuilder res = new StringBuilder();
			while(c<=32)c=nextChar();
			while(c!='\n') {
				res.append(c);
				c=nextChar();
			}
			return res.toString();
		}

		public boolean hasNext() {
			if(c>32)return true;
			while(true) {
				c=nextChar();
				if(c==NC)return false;
				else if(c>32)return true;
			}
		}

		public int[] nextIntArray(int n) {
			int[] res = new int[n];
			for(int i = 0; i < n; i++) res[i] = nextInt();
			return res;
		}

	}

}