//package ecr107;

import java.io.*;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.InputMismatchException;
import java.util.Queue;

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

	void solve()
	{
		int n = ni(), m = ni();
		char[][] ss = new char[n][];
		String[] oss = new String[n];
		for(int i = 0;i < n;i++){
			ss[i] = ns().toCharArray();
			oss[i] = new String(ss[i]);
		}
		int[] offset = new int[n+1];
		offset[0] = 1;
		for(int i = 0;i < n;i++){
			offset[i+1] = offset[i] + ss[i].length-1;
		}
		int U = offset[n]-1;

		final int D = 5;
		int[][] M = new int[(U+1)*D][(U+1)*D];
//		tr(offset);
		for(int i = 0;i < U+1;i++){
			int lb, of;
			if(i == 0) {
				lb = 0;
				of = 0;
			}else{
				lb = lowerBound(offset, i+1) - 1;
				of = i-offset[lb] + 1;
			}
//			tr(i, lb, of, U);

			if(i == 0){
				for(int j = 0;j < n;j++){
					for(int k = 0;k < n;k++){
						if(k != j && oss[k].startsWith(oss[j])){
							M[offset[k]+ss[j].length-1][0+(U+1)*(ss[j].length-1)] = 1;
						}
					}
					M[0][0+(U+1)*(ss[j].length-1)] += 1;
				}
			}else{
				// r: 0 -> 0
				for(int j = 0;j < n;j++){
					if(oss[lb].substring(of).equals(oss[j])){
						M[0][i+(U+1)*(oss[j].length()-1)] += 2;
					}else if(oss[lb].substring(of).startsWith(oss[j])){
						M[i+oss[j].length()][i+(U+1)*(oss[j].length()-1)] += 1;
					}
				}
				// l: -> 0
				String suf = oss[lb].substring(of);
				for(int j = 0;j < n;j++){
					if(oss[j].startsWith(suf) && !oss[j].equals(suf)){
						M[offset[j]+suf.length()-1][i+(U+1)*(suf.length()-1)] += 1;
					}
				}
			}
		}
		for(int i = 0;i < U+1;i++){
			for(int j = 0;j < D-1;j++){
				M[i+(U+1)*(j+1)][i+(U+1)*j] = 1;
			}
		}

//		for(int[] row : M){
//			tr(row);
//		}

		int[] v = new int[(U+1)*D];
		v[0] = 1;
		v = pow(M, v, m);
//		for(int i = 1;i < U+1;i++){
//			if(v[i] != v[i+U]){
//				tr("diff", i, i+U, v[i], v[i+U]);
//			}
//		}
//		tr(v);
		out.println(v[0]);
	}

	///////// begin
	public static final int mod = 998244353;
	public static final long m2 = (long)mod*mod;
	public static final long BIG = 8L*m2;

	// A^e*v
	public static int[] pow(int[][] A, int[] v, long e)
	{
		for(int i = 0;i < v.length;i++){
			if(v[i] >= mod)v[i] %= mod;
		}
		int[][] MUL = A;
		for(;e > 0;e>>>=1) {
			if((e&1)==1)v = mul(MUL, v);
			MUL = p2(MUL);
		}
		return v;
	}

	// int matrix*int vector
	public static int[] mul(int[][] A, int[] v)
	{
		int m = A.length;
		int n = v.length;
		int[] w = new int[m];
		for(int i = 0;i < m;i++){
			long sum = 0;
			for(int k = 0;k < n;k++){
				sum += (long)A[i][k] * v[k];
				if(sum >= BIG)sum -= BIG;
			}
			w[i] = (int)(sum % mod);
		}
		return w;
	}

	// int matrix^2 (be careful about negative value)
	public static int[][] p2(int[][] A)
	{
		int n = A.length;
		int[][] C = new int[n][n];
		for(int i = 0;i < n;i++){
			long[] sum = new long[n];
			for(int k = 0;k < n;k++){
				for(int j = 0;j < n;j++){
					sum[j] += (long)A[i][k] * A[k][j];
					if(sum[j] >= BIG)sum[j] -= BIG;
				}
			}
			for(int j = 0;j < n;j++){
				C[i][j] = (int)(sum[j] % mod);
			}
		}
		return C;
	}

	public static int lowerBound(int[] a, int v){ return lowerBound(a, 0, a.length, v); }
	public static int lowerBound(int[] a, int l, int r, int v)
	{
		if(l > r || l < 0 || r > a.length)throw new IllegalArgumentException();
		int low = l-1, high = r;
		while(high-low > 1){
			int h = high+low>>>1;
			if(a[h] >= v){
				high = h;
			}else{
				low = h;
			}
		}
		return high;
	}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		private FastWriter(){out = null;}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class Solution implements Runnable {

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

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st;

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

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

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

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

	class Edge {
		int b, e, n;
		Edge pr, nt, r;
		Edge(int bb, int ee, int nn, Edge rr, Edge tt) {
			b = bb; e = ee; n = nn; pr = rr; nt = tt;
			r = null;
		}
	}

	Edge[] v;
	Edge cycleEdge;
	int[] ss;

	Edge addedge(int b, int e, int n) {
		Edge r = new Edge(b, e, n, null, v[b]);
		if (v[b] == null) v[b] = r; else v[b] = v[b].pr = r;
		r = new Edge(e, b, n, null, v[e]);
		if (v[e] == null) v[e] = r; else v[e] = v[e].pr = r;
		v[b].r = v[e]; v[e].r = v[b];
		if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
		ss[b]++; ss[e]++;
		return v[b];
	}

	int[] dsu;
	int[] rank;
	Queue<Integer> cc, cp, anss;

	int get(int q) {
		if (dsu[q] != q) return dsu[q] = get(dsu[q]); else return q;
	}

	void uni(int a, int b) {
		a = get(a); b = get(b);
		if (rank[a] == rank[b]) rank[a]++;
		if (rank[a] > rank[b]) dsu[b] = a; else dsu[a] = b;
	}

	int[] w;
	boolean[] ww;

	void ansprint() {
		out.print(anss.size() + " ");
		while (!anss.isEmpty()) out.print(anss.poll() + " ");
		out.println();
	}

	void changeEdge(Edge r, int b, int e) {
		if (r.b != b) changeEdge(r.r, b, e); else {
			ansprint();
			out.println(r.n + " " + b + " " + e);
			r.e = e;
			if (r.r.pr == null) {
				v[r.r.b] = r.r.nt;
			} else {
				r.r.pr.nt = r.r.nt;
			}
			if (r.r.nt != null) r.r.nt.pr = r.r.pr;
			r.r.b = e;
			r.r.nt = v[e];
			r.r.pr = null;
			if (v[e] != null) v[e] = v[e].pr =  r.r; else v[e] = r.r;
		}
	}

	void dfs(int q, int rr) {
		w[q] = 1;
		ww[get(q)] = true;
		if (q != 1) anss.add(q);
		Queue<Edge> obr = new LinkedList<Edge>();
		for (Edge r = v[q]; r != null; r = r.nt) {
			if (r.n != rr) {
				if (w[r.e] == 0) {
					dfs(r.e, r.n);
					anss.add(q);
				}
				obr.add(r);
			}
		}
		while (!obr.isEmpty()) {
			int qq = -1;
			while (!cc.isEmpty() && ww[cc.peek()]) cc.poll();
			if (cc.isEmpty()) {
				while (!cp.isEmpty() && ww[cp.peek()]) cp.poll();
				if (!cp.isEmpty()) qq = cp.poll();
			} else qq = cc.poll();
			if (qq == -1) break;
			Edge r = obr.poll();
			changeEdge(r, q, qq);
			dfs(qq, r.n);
			anss.add(q);
		}
		w[q] = 2;
	}

	Edge[] edges;

	void solve() throws Exception {
		int n = nextInt();
		int m = nextInt();
		if (m == 0) {
			if (n == 1) {
				out.println("YES");
				out.println(0);
				out.println("1 1");
			} else {
				out.println("NO");
			}
			return;
		}
		v = new Edge[n + 1];
		dsu = new int[n + 1];
		rank = new int[n + 1];
		ss = new int[n + 1];
		edges = new Edge[m + 1];
		for (int i = 1; i <= n; i++) dsu[i] = i;
		for (int i = 1; i <= m; i++) {
			edges[i] = addedge(nextInt(), nextInt(), i);
		}
		cc = new LinkedList<Integer>();
		cp = new LinkedList<Integer>();
		int cs = 0;
		for (int i = 1; i <= n; i++)
			if (dsu[i] == i && i != get(1)) {
				cs++;
			}
		if (cs > m || cs == m && cycleEdge == null && ss[1] == 0) {
			out.println("NO");
		} else {
			out.println("YES");
			if (ss[1] == 0 && cycleEdge == null) cs++;
			out.println(cs);
			ww = new boolean[n + 1];
			w = new int[n + 1];
			anss = new LinkedList<Integer>();
			anss.add(1);
			if (ss[1] == 0) {
				if (cycleEdge != null) {
					changeEdge(cycleEdge, cycleEdge.b, 1);
				} else {
					int j = 2;
					while (ss[j] != 1) j++;
					changeEdge(v[j], v[j].e, 1);
					cp.add(j);
				}
				for (int i = 1; i <= n; i++) { dsu[i] = i; rank[i] = 0; ss[i] = 0; }
				for (int i = 1; i <= m; i++) {
					int b = edges[i].b;
					int e = edges[i].e;
					if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
					ss[b]++; ss[e]++;
				}
				for (int i = 1; i <= n; i++)
					if (dsu[i] == i && i != get(1)) {
						if (rank[i] == 0) cp.add(i); else cc.add(i);
					}
			}
			dfs(1, 0);
			ansprint();
		}
	}

	public void run() {
		Locale.setDefault(Locale.UK);
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		} finally {
			out.flush();
		}
	}

}


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class Solution implements Runnable {

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

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st;

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

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

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

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

	class Edge {
		int b, e, n;
		Edge pr, nt, r;
		Edge(int bb, int ee, int nn, Edge rr, Edge tt) {
			b = bb; e = ee; n = nn; pr = rr; nt = tt;
			r = null;
		}
	}

	Edge[] v;
	Edge cycleEdge;
	int[] ss;

	void addedge(int b, int e, int n) {
		Edge r = new Edge(b, e, n, null, v[b]);
		if (v[b] == null) v[b] = r; else v[b] = v[b].pr = r;
		r = new Edge(e, b, n, null, v[e]);
		if (v[e] == null) v[e] = r; else v[e] = v[e].pr = r;
		v[b].r = v[e]; v[e].r = v[b];
		if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
		ss[b]++; ss[e]++;
	}

	int[] dsu;
	int[] rank;
	Queue<Integer> cc, cp, anss;

	int get(int q) {
		if (dsu[q] != q) return dsu[q] = get(dsu[q]); else return q;
	}

	void uni(int a, int b) {
		a = get(a); b = get(b);
		if (rank[a] == rank[b]) rank[a]++;
		if (rank[a] > rank[b]) dsu[b] = a; else dsu[a] = b;
	}

	int[] w;
	boolean[] ww;

	void ansprint() {
		out.print(anss.size() + " ");
		while (!anss.isEmpty()) out.print(anss.poll() + " ");
		out.println();
	}

	void changeEdge(Edge r, int b, int e) {
		if (r.b != b) changeEdge(r.r, b, e); else {
			ansprint();
			out.println(r.n + " " + b + " " + e);
			r.e = e;
			if (r.r.pr == null) {
				v[r.r.b] = r.r.nt;
			} else {
				r.r.pr.nt = r.r.nt;
			}
			if (r.r.nt != null) r.r.nt.pr = r.r.pr;
			r.r.b = e;
			r.r.nt = v[e];
			r.r.pr = null;
			if (v[e] != null) v[e] = v[e].pr =  r.r; else v[e] = r.r;
		}
	}

	void dfs(int q, int rr) {
		w[q] = 1;
		ww[get(q)] = true;
		if (q != 1) anss.add(q);
		Queue<Edge> obr = new LinkedList<Edge>();
		for (Edge r = v[q]; r != null; r = r.nt) {
			if (r.n != rr) {
				if (w[r.e] == 0) {
					dfs(r.e, r.n);
					anss.add(q);
				}
				obr.add(r);
			}
		}
		while (!obr.isEmpty()) {
			int qq = -1;
			while (!cc.isEmpty() && ww[cc.peek()]) cc.poll();
			if (cc.isEmpty()) {
				while (!cp.isEmpty() && ww[cp.peek()]) cp.poll();
				if (!cp.isEmpty()) qq = cp.poll();
			} else qq = cc.poll();
			if (qq == -1) break;
			Edge r = obr.poll();
			changeEdge(r, q, qq);
			dfs(qq, r.n);
			anss.add(q);
		}
		w[q] = 2;
	}

	void solve() throws Exception {
		int n = nextInt();
		int m = nextInt();
		if (m == 0) {
			if (n == 1) {
				out.println("YES");
				out.println(0);
				out.println("1 1");
			} else {
				out.println("NO");
			}
			return;
		}
		v = new Edge[n + 1];
		dsu = new int[n + 1];
		rank = new int[n + 1];
		ss = new int[n + 1];
		for (int i = 1; i <= n; i++) dsu[i] = i;
		for (int i = 1; i <= m; i++) {
			addedge(nextInt(), nextInt(), i);
		}
		cc = new LinkedList<Integer>();
		cp = new LinkedList<Integer>();
		int cs = 0;
		for (int i = 1; i <= n; i++)
			if (dsu[i] == i && i != get(1)) {
				cs++;
				if (rank[i] == 0) cp.add(i); else cc.add(i);
			}
		if (cs > m || cs == m && cycleEdge == null && ss[1] == 0) {
			out.println("NO");
		} else {
			out.println("YES");
			if (ss[1] == 0 && cycleEdge == null) cs++;
			out.println(cs);
			ww = new boolean[n + 1];
			w = new int[n + 1];
			anss = new LinkedList<Integer>();
			anss.add(1);
			if (ss[1] == 0) {
				if (cycleEdge != null) {
					changeEdge(cycleEdge, cycleEdge.b, 1);
				} else {
					int j = 2;
					while (ss[j] != 1) j++;
					changeEdge(v[j], v[j].e, 1);
					cp.add(j);
				}
			}
			dfs(1, 0);
			ansprint();
		}
	}

	public void run() {
		Locale.setDefault(Locale.UK);
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		} finally {
			out.flush();
		}
	}

}


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class Solution implements Runnable {

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

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st;

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

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

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

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

	class Edge {
		int b, e, n;
		boolean move;
		Edge pr, nt, r;
		Edge(int bb, int ee, int nn, Edge rr, Edge tt) {
			b = bb; e = ee; n = nn; pr = rr; nt = tt;
			r = null;
			move = false;
		}
	}

	Edge[] v;
	Edge cycleEdge;
	int[] ss;

	Edge addedge(int b, int e, int n) {
		Edge r = new Edge(b, e, n, null, v[b]);
		if (v[b] == null) v[b] = r; else v[b] = v[b].pr = r;
		r = new Edge(e, b, n, null, v[e]);
		if (v[e] == null) v[e] = r; else v[e] = v[e].pr = r;
		v[b].r = v[e]; v[e].r = v[b];
		if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
		ss[b]++; ss[e]++;
		return v[b];
	}

	int[] dsu;
	int[] rank;
	Queue<Integer> cc, cp, anss;

	int get(int q) {
		if (dsu[q] != q) return dsu[q] = get(dsu[q]); else return q;
	}

	void uni(int a, int b) {
		a = get(a); b = get(b);
		if (rank[a] == rank[b]) rank[a]++;
		if (rank[a] > rank[b]) dsu[b] = a; else dsu[a] = b;
	}

	int[] w;
	boolean[] ww;

	void ansprint() {
		out.print(anss.size() + " ");
		while (!anss.isEmpty()) out.print(anss.poll() + " ");
		out.println();
	}

	void changeEdge(Edge r, int b, int e) {
		if (r.b != b) changeEdge(r.r, b, e); else {
			ansprint();
			out.println(r.n + " " + b + " " + e);
			r.e = e;
			if (r.r.pr == null) {
				v[r.r.b] = r.r.nt;
			} else {
				r.r.pr.nt = r.r.nt;
			}
			if (r.r.nt != null) r.r.nt.pr = r.r.pr;
			r.r.b = e;
			r.r.nt = v[e];
			r.r.pr = null;
			if (v[e] != null) v[e] = v[e].pr =  r.r; else v[e] = r.r;
			r.move = r.r.move = true;
		}
	}

	void dfs(int q, int rr) {
		w[q] = 1;
		ww[get(q)] = true;
		if (q != 1) anss.add(q);
		Queue<Edge> obr = new LinkedList<Edge>();
		for (Edge r = v[q]; r != null; r = r.nt) {
			if (r.n != rr) {
				if (w[r.e] == 0) {
					dfs(r.e, r.n);
					anss.add(q);
				}
				if (!r.move) obr.add(r);
			}
		}
		while (!obr.isEmpty()) {
			int qq = -1;
			while (!cc.isEmpty() && ww[cc.peek()]) cc.poll();
			if (cc.isEmpty()) {
				while (!cp.isEmpty() && ww[cp.peek()]) cp.poll();
				if (!cp.isEmpty()) qq = cp.poll();
			} else qq = cc.poll();
			if (qq == -1) break;
			Edge r = obr.poll();
			changeEdge(r, q, qq);
			dfs(qq, r.n);
			anss.add(q);
		}
		w[q] = 2;
	}

	Edge[] edges;

	void solve() throws Exception {
		int n = nextInt();
		int m = nextInt();
		if (m == 0) {
			if (n == 1) {
				out.println("YES");
				out.println(0);
				out.println("1 1");
			} else {
				out.println("NO");
			}
			return;
		}
		v = new Edge[n + 1];
		dsu = new int[n + 1];
		rank = new int[n + 1];
		ss = new int[n + 1];
		edges = new Edge[m + 1];
		for (int i = 1; i <= n; i++) dsu[i] = i;
		for (int i = 1; i <= m; i++) {
			edges[i] = addedge(nextInt(), nextInt(), i);
		}
		cc = new LinkedList<Integer>();
		cp = new LinkedList<Integer>();
		int cs = 0;
		for (int i = 1; i <= n; i++)
			if (dsu[i] == i && i != get(1)) {
				cs++;
			}
		if (cs > m || cs == m && cycleEdge == null && ss[1] == 0) {
			out.println("NO");
		} else {
			out.println("YES");
			if (ss[1] == 0 && cycleEdge == null) cs++;
			out.println(cs);
			ww = new boolean[n + 1];
			w = new int[n + 1];
			anss = new LinkedList<Integer>();
			anss.add(1);
			if (ss[1] == 0) {
				if (cycleEdge != null) {
					changeEdge(cycleEdge, cycleEdge.b, 1);
				} else {
					int j = 2;
					while (ss[j] != 1 || ss[v[j].e] == 1) j++;
					changeEdge(v[j], v[j].e, 1);
					cp.add(j);
				}
			}
			for (int i = 1; i <= n; i++) { dsu[i] = i; rank[i] = 0; ss[i] = 0; }
			for (int i = 1; i <= m; i++) {
				int b = edges[i].b;
				int e = edges[i].e;
				if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
				ss[b]++; ss[e]++;
			}
			for (int i = 1; i <= n; i++)
				if (dsu[i] == i && i != get(1)) {
					if (rank[i] == 0) cp.add(i); else cc.add(i);
				}
			dfs(1, 0);
			ansprint();
		}
	}

	public void run() {
		Locale.setDefault(Locale.UK);
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		} finally {
			out.flush();
		}
	}

}


import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Locale;
import java.util.Queue;
import java.util.Random;
import java.util.StringTokenizer;
import java.util.TreeMap;
import java.util.TreeSet;

public class Solution implements Runnable {

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

	BufferedReader in;
	PrintWriter out;
	StringTokenizer st;

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

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

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

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

	class Edge {
		int b, e, n;
		Edge pr, nt, r;
		Edge(int bb, int ee, int nn, Edge rr, Edge tt) {
			b = bb; e = ee; n = nn; pr = rr; nt = tt;
			r = null;
		}
	}

	Edge[] v;
	Edge cycleEdge;
	int[] ss;

	void addedge(int b, int e, int n) {
		Edge r = new Edge(b, e, n, null, v[b]);
		if (v[b] == null) v[b] = r; else v[b] = v[b].pr = r;
		r = new Edge(e, b, n, null, v[e]);
		if (v[e] == null) v[e] = r; else v[e] = v[e].pr = r;
		v[b].r = v[e]; v[e].r = v[b];
		if (get(b) != get(e)) uni(b, e); else cycleEdge = v[e];
		ss[b]++; ss[e]++;
	}

	int[] dsu;
	int[] rank;
	Queue<Integer> cc, cp, anss;

	int get(int q) {
		if (dsu[q] != q) return dsu[q] = get(dsu[q]); else return q;
	}

	void uni(int a, int b) {
		a = get(a); b = get(b);
		if (rank[a] == rank[b]) rank[a]++;
		if (rank[a] > rank[b]) dsu[b] = a; else dsu[a] = b;
	}

	int[] w;
	boolean[] ww;

	void ansprint() {
		out.print(anss.size() + " ");
		while (!anss.isEmpty()) out.print(anss.poll() + " ");
		out.println();
	}

	void changeEdge(Edge r, int b, int e) {
		if (r.b != b) changeEdge(r.r, b, e); else {
			ansprint();
			out.println(r.n + " " + b + " " + e);
			r.e = e;
			if (r.r.pr == null) {
				v[r.r.b] = r.r.nt;
			} else {
				r.r.pr.nt = r.r.nt;
			}
			if (r.r.nt != null) r.r.nt.pr = r.r.pr;
			r.r.b = b;
			r.r.nt = v[b];
			r.r.pr = null;
			v[b] = v[b].pr =  r.r;
		}
	}

	void dfs(int q, int rr) {
		w[q] = 1;
		ww[get(q)] = true;
		anss.add(q);
		Queue<Edge> obr = new LinkedList<Edge>();
		for (Edge r = v[q]; r != null; r = r.nt) {
			if (r.n != rr) {
				if (w[r.e] == 0) {
					dfs(r.e, r.n);
					anss.add(q);
				}
				obr.add(r);
			}
		}
		while (!obr.isEmpty()) {
			int qq = -1;
			while (!cc.isEmpty() && ww[cc.peek()]) cc.poll();
			if (cc.isEmpty()) {
				while (!cp.isEmpty() && ww[cp.peek()]) cp.poll();
				if (!cp.isEmpty()) qq = cp.poll();
			} else qq = cc.poll();
			if (qq == -1) break;
			Edge r = obr.poll();
			changeEdge(r, q, qq);
			dfs(qq, r.n);
			anss.add(q);
		}
		w[q] = 2;
	}

	void solve() throws Exception {
		int n = nextInt();
		int m = nextInt();
		if (m == 0) {
			if (n == 1) {
				out.println("YES");
				out.println(0);
				out.println("1 1");
			} else {
				out.println("NO");
			}
			return;
		}
		v = new Edge[n + 1];
		dsu = new int[n + 1];
		rank = new int[n + 1];
		ss = new int[n + 1];
		for (int i = 1; i <= n; i++) dsu[i] = i;
		for (int i = 1; i <= m; i++) {
			addedge(nextInt(), nextInt(), i);
		}
		cc = new LinkedList<Integer>();
		cp = new LinkedList<Integer>();
		int cs = 0;
		for (int i = 1; i <= n; i++)
			if (dsu[i] == i && i != get(1)) {
				cs++;
				if (rank[i] == 0) cp.add(i); else cc.add(i);
			}
		if (cs > m || cs == m && cycleEdge == null && ss[1] == 0) {
			out.println("NO");
		} else {
			out.println("YES");
			ww = new boolean[n + 1];
			w = new int[n + 1];
			anss = new LinkedList<Integer>();
			if (ss[1] == 0) {
				anss.add(1);
				if (cycleEdge != null) {
					changeEdge(cycleEdge, 1, cycleEdge.e);
				} else {
					int j = 2;
					while (ss[j] != 1) j++;
					changeEdge(v[j], 1, v[j].e);
					cp.add(j);
					cs++;
				}
			}
			out.println(cs);
			dfs(1, 0);
			ansprint();
		}
	}

	public void run() {
		Locale.setDefault(Locale.UK);
		try {
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintWriter(System.out);
			solve();
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(1);
		} finally {
			out.flush();
		}
	}

}


import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.BufferedReader;
import java.util.Comparator;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Random;
import java.util.TreeSet;
import java.util.StringTokenizer;
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;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskD solver = new TaskD();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskD {
    static class Point {
        int x;
        int y;
        int index;

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

    static class GraphNode implements Comparable<GraphNode> {
        int sideId;
        int x;
        double y;
        double distance = 1e100;
        boolean mark = false;

        List<GraphNode> outgo = new ArrayList<GraphNode>();

        GraphNode(int sideId, int x) {
            this.sideId = sideId;
            this.x = x;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            GraphNode graphNode = (GraphNode) o;

            if (sideId != graphNode.sideId) return false;
            if (x != graphNode.x) return false;

            return true;
        }

        public int hashCode() {
            int result = sideId;
            result = 31 * result + x;
            return result;
        }

        public int compareTo(GraphNode graphNode) {
            int z = sideId - graphNode.sideId;
            if (z != 0) return z;
            return x - graphNode.x;
        }
    }

    List<GraphNode> nodes = new ArrayList<GraphNode>();
    Map<GraphNode, GraphNode> canonical = new HashMap<GraphNode, GraphNode>();

    static class Edge implements Comparable<Edge> {
        Point v1;
        Point v2;
        int isUpper;

        Edge(Point v1, Point v2) {
            if (v1.x > v2.x) {
                Point tmp = v1;
                v1 = v2;
                v2 = tmp;
            }
            this.v1 = v1;
            this.v2 = v2;
        }

        public int compareTo(Edge edge) {
            int minx = Math.max(v1.x, edge.v1.x);
            int maxx = Math.min(v2.x, edge.v2.x);
            if (minx >= maxx) {
                throw new RuntimeException();
            }
            //if (this.v1 == edge.v1 && this.v2 == edge.v2) return 0;
            int mid = (minx + maxx) / 2;
            long diff = ((mid - v1.x) * (long) (v2.y - v1.y) + v1.y * (long) (v2.x - v1.x)) * (edge.v2.x - edge.v1.x)
                    - ((mid - edge.v1.x) * (long) (edge.v2.y - edge.v1.y) + edge.v1.y * (long) (edge.v2.x - edge.v1.x)) * (v2.x - v1.x);
            return Long.signum(diff);
        }
    }

    int n;

	public void solve(int testNumber, InputReader in, PrintWriter out) {
        Random random = new Random(5943715431L);
        n = in.nextInt();
        Point[] poly = new Point[n];
        for (int i = 0; i < n; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            poly[i] = new Point(x * 2, y * 2, i);
        }
        for (int i = 0; i < poly.length; ++i) {
            Edge e1 = new Edge(poly[i], poly[(i + 1) % poly.length]);
            Edge e2 = new Edge(poly[i], poly[(i + poly.length - 1) % poly.length]);
            addTransition(e1, e2, poly[i].x);
            addTransition(e2, e1, poly[i].x);
        }
        int s = in.nextInt() - 1;
        int t = in.nextInt() - 1;
        TreeSet<Edge> picture = new TreeSet<Edge>();
        Point[] polyByX = poly.clone();
        for (int i = 0; i < polyByX.length; ++i) {
            int j = i + random.nextInt(polyByX.length - i);
            Point tmp = polyByX[i];
            polyByX[i] = polyByX[j];
            polyByX[j] = tmp;
        }
        Arrays.sort(polyByX, new Comparator<Point>() {
            public int compare(Point a, Point b) {
                int z = Integer.signum(a.x - b.x);
                if (z != 0) return z;
                return Integer.signum(a.y - b.y);
            }
        });
        for (int pi = 0; pi < polyByX.length;) {
            int pj;
            Point prevP = null;
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x > b.x || (a.x == b.x && a.y > b.y)) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x < p.x && b.x < p.x) {
                    if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) < 0) {
                        Point tmp = a;
                        a = b;
                        b = tmp;
                    }
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 2) {
                        Edge dest = picture.lower(bEdge);
                        double destY = addTransition(bEdge, dest, p.x);
                        if (prevP != null) {
                            if (prevP.y > destY) {
                                getNodeFor(poly, p.index).outgo.add(getNodeFor(poly, prevP.index));
                            }
                        }
                    }
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    }
                } else if (a.x < p.x && b.x > p.x) {
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    } else {
                        Edge dest = picture.lower(aEdge);
                        double destY = addTransition(aEdge, dest, p.x);
                        if (prevP != null) {
                            if (prevP.y > destY) {
                                getNodeFor(poly, p.index).outgo.add(getNodeFor(poly, prevP.index));
                            }
                        }
                    }
                } else if (a.x < p.x && b.x == p.x) {
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1 && b.y < p.y) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    } else if (aEdge.isUpper == 2 && b.y > p.y) {
                        Edge dest = picture.lower(aEdge);
                        double destY = addTransition(aEdge, dest, p.x);
                        if (prevP != null) {
                            if (prevP.y > destY) {
                                getNodeFor(poly, p.index).outgo.add(getNodeFor(poly, prevP.index));
                            }
                        }
                    }
                }
                prevP = p;
            }
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x < p.x) {
                    Edge toRemove = new Edge(a, p);
                    if (!picture.remove(toRemove)) throw new RuntimeException();
                }
                if (b.x < p.x) {
                    Edge toRemove = new Edge(b, p);
                    if (!picture.remove(toRemove)) {
                        throw new RuntimeException();
                    }
                }
            }
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) < 0) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x > p.x) {
                    Edge toAdd = new Edge(a, p);
                    Edge prev = picture.lower(toAdd);
                    if (prev == null)
                        toAdd.isUpper = 1;
                    else
                        toAdd.isUpper = 3 - prev.isUpper;
                    if (!picture.add(toAdd)) throw new RuntimeException();
                }
                if (b.x > p.x) {
                    Edge toAdd = new Edge(b, p);
                    Edge prev = picture.lower(toAdd);
                    if (prev == null)
                        toAdd.isUpper = 1;
                    else
                        toAdd.isUpper = 3 - prev.isUpper;
                    if (!picture.add(toAdd)) throw new RuntimeException();
                }
            }
            prevP = null;
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x > b.x || (a.x == b.x && a.y > b.y)) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x > p.x && b.x > p.x) {
                    if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) > 0) {
                        Point tmp = a;
                        a = b;
                        b = tmp;
                    }
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 2) {
                        Edge dest = picture.lower(bEdge);
                        double destY = addTransition(bEdge, dest, p.x);
                        if (prevP != null) {
                            if (prevP.y > destY) {
                                getNodeFor(poly, p.index).outgo.add(getNodeFor(poly, prevP.index));
                            }
                        }
                    }
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    }
                } else if (a.x == p.x && b.x > p.x) {
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 1 && a.y < p.y) {
                        Edge dest = picture.higher(bEdge);
                        addTransition(dest, bEdge, p.x);
                    } else if (bEdge.isUpper == 2 && a.y > p.y) {
                        Edge dest = picture.lower(bEdge);
                        double destY = addTransition(bEdge, dest, p.x);
                        if (prevP != null) {
                            if (prevP.y > destY) {
                                getNodeFor(poly, p.index).outgo.add(getNodeFor(poly, prevP.index));
                            }
                        }
                    }
                }
                prevP = p;
            }
            pi = pj;
        }
        GraphNode start = getNodeFor(poly, s);
        GraphNode finish = getNodeFor(poly, t);
        Collections.sort(nodes);
        for (int i = 0; i + 1 < nodes.size(); ++i) {
            GraphNode n1 = nodes.get(i);
            GraphNode n2 = nodes.get(i + 1);
            if (n1.sideId == n2.sideId) {
                n1.outgo.add(n2);
                n2.outgo.add(n1);
            }
        }
        TreeSet<Reach> reaches = new TreeSet<Reach>();
        start.distance = 0;
        reaches.add(new Reach(start, 0));
        while (true) {
            Reach first = reaches.pollFirst();
            if (first.dest.mark) continue;
            first.dest.mark = true;
            if (first.dest == finish) {
                out.println(first.dest.distance / 2.0);
                return;
            }
            for (GraphNode other : first.dest.outgo) {
                double dx = first.dest.x - other.x;
                double dy = first.dest.y - other.y;
                double dd = Math.sqrt(dx * dx + dy * dy);
                double nd = first.dest.distance + dd;
                if (nd < other.distance - 1e-10) {
                    other.distance = nd;
                    reaches.add(new Reach(other, other.distance));
                }
            }
        }
	}

    private GraphNode getNodeFor(Point[] poly, int s) {
        GraphNode start;
        {
            Point sp = poly[s];
            Point spa = poly[(s + 1) % poly.length];
            Point spb = poly[(s + poly.length - 1) % poly.length];
            if (spa.x != sp.x || spa.y > sp.y) {
                start = createNode(new Edge(sp, spa), sp.x);
            } else {
                start = createNode(new Edge(sp, spb), sp.x);
            }
        }
        return start;
    }

    static class Reach implements Comparable<Reach> {
        GraphNode dest;
        double d;

        Reach(GraphNode dest, double d) {
            this.dest = dest;
            this.d = d;
        }

        public int compareTo(Reach reach) {
            if (d != reach.d) return Double.compare(d, reach.d);
            return dest.compareTo(reach.dest);
        }
    }

    private double addTransition(Edge top, Edge bottom, int x) {
        GraphNode src = createNode(top, x);
        GraphNode dst = createNode(bottom, x);
        src.outgo.add(dst);
        return dst.y;
    }

    private GraphNode createNode(Edge top, int x) {
        GraphNode src;
        {
            int i1 = top.v1.index;
            int i2 = top.v2.index;
            int i;
            if (i1 + 1 == i2 || i1 + 1 == i2 + n) {
                i = i1;
            } else if (i2 + 1 == i1 || i2 + 1 == i1 + n) {
                i = i2;
            } else {
                throw new RuntimeException();
            }
            src = new GraphNode(i, x);
            GraphNode canonicalSrc = canonical.get(src);
            if (canonicalSrc == null) {
                canonical.put(src, src);
                nodes.add(src);
                if (top.v1.x == top.v2.x)
                    src.y = Math.min(top.v1.y, top.v2.y);
                else
                    src.y = (x - top.v1.x) / (double) (top.v2.x - top.v1.x) * (top.v2.y - top.v1.y) + top.v1.y;
            } else {
                src = canonicalSrc;
            }
        }
        return src;
    }
}

class InputReader {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

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

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

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

    }


import java.util.List;
import java.util.Map;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.ArrayList;
import java.util.HashMap;
import java.io.BufferedReader;
import java.util.Comparator;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Random;
import java.util.TreeSet;
import java.util.StringTokenizer;
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;
		InputReader in = new InputReader(inputStream);
		PrintWriter out = new PrintWriter(outputStream);
		TaskD solver = new TaskD();
		solver.solve(1, in, out);
		out.close();
	}
}

class TaskD {
    static class Point {
        int x;
        int y;
        int index;

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

    static class GraphNode implements Comparable<GraphNode> {
        int sideId;
        int x;
        double y;
        double distance = 1e100;
        boolean mark = false;

        List<GraphNode> outgo = new ArrayList<GraphNode>();

        GraphNode(int sideId, int x) {
            this.sideId = sideId;
            this.x = x;
        }

        public boolean equals(Object o) {
            if (this == o) return true;
            GraphNode graphNode = (GraphNode) o;

            if (sideId != graphNode.sideId) return false;
            if (x != graphNode.x) return false;

            return true;
        }

        public int hashCode() {
            int result = sideId;
            result = 31 * result + x;
            return result;
        }

        public int compareTo(GraphNode graphNode) {
            int z = sideId - graphNode.sideId;
            if (z != 0) return z;
            return x - graphNode.x;
        }
    }

    List<GraphNode> nodes = new ArrayList<GraphNode>();
    Map<GraphNode, GraphNode> canonical = new HashMap<GraphNode, GraphNode>();

    static class Edge implements Comparable<Edge> {
        Point v1;
        Point v2;
        int isUpper;

        Edge(Point v1, Point v2) {
            if (v1.x > v2.x) {
                Point tmp = v1;
                v1 = v2;
                v2 = tmp;
            }
            this.v1 = v1;
            this.v2 = v2;
        }

        public int compareTo(Edge edge) {
            int minx = Math.max(v1.x, edge.v1.x);
            int maxx = Math.min(v2.x, edge.v2.x);
            if (minx >= maxx) {
                throw new RuntimeException();
            }
            //if (this.v1 == edge.v1 && this.v2 == edge.v2) return 0;
            int mid = (minx + maxx) / 2;
            long diff = ((mid - v1.x) * (long) (v2.y - v1.y) + v1.y * (long) (v2.x - v1.x)) * (edge.v2.x - edge.v1.x)
                    - ((mid - edge.v1.x) * (long) (edge.v2.y - edge.v1.y) + edge.v1.y * (long) (edge.v2.x - edge.v1.x)) * (v2.x - v1.x);
            return Long.signum(diff);
        }
    }

    int n;

	public void solve(int testNumber, InputReader in, PrintWriter out) {
        Random random = new Random(5943715431L);
        n = in.nextInt();
        Point[] poly = new Point[n];
        for (int i = 0; i < n; ++i) {
            int x = in.nextInt();
            int y = in.nextInt();
            poly[i] = new Point(x * 2, y * 2, i);
        }
        for (int i = 0; i < poly.length; ++i) {
            Edge e1 = new Edge(poly[i], poly[(i + 1) % poly.length]);
            Edge e2 = new Edge(poly[i], poly[(i + poly.length - 1) % poly.length]);
            addTransition(e1, e2, poly[i].x);
            addTransition(e2, e1, poly[i].x);
        }
        int s = in.nextInt() - 1;
        int t = in.nextInt() - 1;
        TreeSet<Edge> picture = new TreeSet<Edge>();
        Point[] polyByX = poly.clone();
        for (int i = 0; i < polyByX.length; ++i) {
            int j = i + random.nextInt(polyByX.length - i);
            Point tmp = polyByX[i];
            polyByX[i] = polyByX[j];
            polyByX[j] = tmp;
        }
        Arrays.sort(polyByX, new Comparator<Point>() {
            public int compare(Point a, Point b) {
                int z = Integer.signum(a.x - b.x);
                if (z != 0) return z;
                return Integer.signum(a.y - b.y);
            }
        });
        for (int pi = 0; pi < polyByX.length;) {
            int pj;
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x > b.x || (a.x == b.x && a.y > b.y)) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x < p.x && b.x < p.x) {
                    if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) < 0) {
                        Point tmp = a;
                        a = b;
                        b = tmp;
                    }
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 2) {
                        Edge dest = picture.lower(bEdge);
                        addTransition(bEdge, dest, p.x);
                    }
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    }
                } else if (a.x < p.x && b.x > p.x) {
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    } else {
                        Edge dest = picture.lower(aEdge);
                        addTransition(aEdge, dest, p.x);
                    }
                } else if (a.x < p.x && b.x == p.x) {
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1 && b.y < p.y) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    } else if (aEdge.isUpper == 2 && b.y > p.y) {
                        Edge dest = picture.lower(aEdge);
                        addTransition(aEdge, dest, p.x);
                    }
                }
            }
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x < p.x) {
                    Edge toRemove = new Edge(a, p);
                    if (!picture.remove(toRemove)) throw new RuntimeException();
                }
                if (b.x < p.x) {
                    Edge toRemove = new Edge(b, p);
                    if (!picture.remove(toRemove)) {
                        throw new RuntimeException();
                    }
                }
            }
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) < 0) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x > p.x) {
                    Edge toAdd = new Edge(a, p);
                    Edge prev = picture.lower(toAdd);
                    if (prev == null)
                        toAdd.isUpper = 1;
                    else
                        toAdd.isUpper = 3 - prev.isUpper;
                    if (!picture.add(toAdd)) throw new RuntimeException();
                }
                if (b.x > p.x) {
                    Edge toAdd = new Edge(b, p);
                    Edge prev = picture.lower(toAdd);
                    if (prev == null)
                        toAdd.isUpper = 1;
                    else
                        toAdd.isUpper = 3 - prev.isUpper;
                    if (!picture.add(toAdd)) throw new RuntimeException();
                }
            }
            for (pj = pi; pj < polyByX.length && polyByX[pj].x == polyByX[pi].x; ++pj) {
                Point p = polyByX[pj];
                Point a = poly[(p.index + 1) % poly.length];
                Point b = poly[(p.index + poly.length - 1) % poly.length];
                if (a.x > b.x || (a.x == b.x && a.y > b.y)) {
                    Point tmp = a;
                    a = b;
                    b = tmp;
                }
                if (a.x > p.x && b.x > p.x) {
                    if ((a.x - p.x) * (long) (b.y - p.y) - (a.y - p.y) * (long) (b.x - p.x) > 0) {
                        Point tmp = a;
                        a = b;
                        b = tmp;
                    }
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 2) {
                        Edge dest = picture.lower(bEdge);
                        addTransition(bEdge, dest, p.x);
                    }
                    Edge aEdge = picture.floor(new Edge(a, p));
                    if (aEdge.isUpper == 1) {
                        Edge dest = picture.higher(aEdge);
                        addTransition(dest, aEdge, p.x);
                    }
                } else if (a.x == p.x && b.x > p.x) {
                    Edge bEdge = picture.floor(new Edge(b, p));
                    if (bEdge.isUpper == 1 && a.y < p.y) {
                        Edge dest = picture.higher(bEdge);
                        addTransition(dest, bEdge, p.x);
                    } else if (bEdge.isUpper == 2 && a.y > p.y) {
                        Edge dest = picture.lower(bEdge);
                        addTransition(bEdge, dest, p.x);
                    }
                }
            }
            pi = pj;
        }
        GraphNode start;
        {
            Point sp = poly[s];
            Point spa = poly[(s + 1) % poly.length];
            Point spb = poly[(s + poly.length - 1) % poly.length];
            if (spa.x != sp.x || spa.y > sp.y) {
                start = createNode(new Edge(sp, spa), sp.x);
            } else {
                start = createNode(new Edge(sp, spb), sp.x);
            }
        }
        GraphNode finish;
        {
            Point sp = poly[t];
            Point spa = poly[(t + 1) % poly.length];
            Point spb = poly[(t + poly.length - 1) % poly.length];
            if (spa.x != sp.x || spa.y > sp.y) {
                finish = createNode(new Edge(sp, spa), sp.x);
            } else {
                finish = createNode(new Edge(sp, spb), sp.x);
            }
        }
        Collections.sort(nodes);
        for (int i = 0; i + 1 < nodes.size(); ++i) {
            GraphNode n1 = nodes.get(i);
            GraphNode n2 = nodes.get(i + 1);
            if (n1.sideId == n2.sideId) {
                n1.outgo.add(n2);
                n2.outgo.add(n1);
            }
        }
        TreeSet<Reach> reaches = new TreeSet<Reach>();
        start.distance = 0;
        reaches.add(new Reach(start, 0));
        while (true) {
            Reach first = reaches.pollFirst();
            if (first.dest.mark) continue;
            first.dest.mark = true;
            if (first.dest == finish) {
                out.println(first.dest.distance / 2.0);
                return;
            }
            for (GraphNode other : first.dest.outgo) {
                double dx = first.dest.x - other.x;
                double dy = first.dest.y - other.y;
                double dd = Math.sqrt(dx * dx + dy * dy);
                double nd = first.dest.distance + dd;
                if (nd < other.distance - 1e-10) {
                    other.distance = nd;
                    reaches.add(new Reach(other, other.distance));
                }
            }
        }
	}

    static class Reach implements Comparable<Reach> {
        GraphNode dest;
        double d;

        Reach(GraphNode dest, double d) {
            this.dest = dest;
            this.d = d;
        }

        public int compareTo(Reach reach) {
            if (d != reach.d) return Double.compare(d, reach.d);
            return dest.compareTo(reach.dest);
        }
    }

    private void addTransition(Edge top, Edge bottom, int x) {
        GraphNode src = createNode(top, x);
        GraphNode dst = createNode(bottom, x);
        src.outgo.add(dst);
    }

    private GraphNode createNode(Edge top, int x) {
        GraphNode src;
        {
            int i1 = top.v1.index;
            int i2 = top.v2.index;
            int i;
            if (i1 + 1 == i2 || i1 + 1 == i2 + n) {
                i = i1;
            } else if (i2 + 1 == i1 || i2 + 1 == i1 + n) {
                i = i2;
            } else {
                throw new RuntimeException();
            }
            src = new GraphNode(i, x);
            GraphNode canonicalSrc = canonical.get(src);
            if (canonicalSrc == null) {
                canonical.put(src, src);
                nodes.add(src);
                if (top.v1.x == top.v2.x)
                    src.y = Math.min(top.v1.y, top.v2.y);
                else
                    src.y = (x - top.v1.x) / (double) (top.v2.x - top.v1.x) * (top.v2.y - top.v1.y) + top.v1.y;
            } else {
                src = canonicalSrc;
            }
        }
        return src;
    }
}

class InputReader {
    private BufferedReader reader;
    private StringTokenizer tokenizer;

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

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

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

    }


import java.util.Scanner;

public class Problem131A {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		String x = sc.next();
		sc.close();
		char[] y = x.toCharArray();
		boolean allcaps = true;
		boolean firstsmallrestcaps = true;
		for (int i = 0; i < y.length; i++) {
			if (allcaps) {
				if ('a' <= y[i] && y[i] <= 'z') {
					allcaps = false;
				}
			}
			if (firstsmallrestcaps) {
				if (i == 0 && 'A' <= y[i] && y[i] <= 'Z') {
					firstsmallrestcaps = false;
				} else if (i != 0 && 'a' <= y[i] && y[i] <= 'z') {
					firstsmallrestcaps = false;
				}
			}
		}
		if (allcaps || firstsmallrestcaps) {
			for (int i = 0; i < y.length; i++) {
				if (y[i] >= 'A' && y[i] <= 'Z') {
					y[i] = (char) (y[i] + 'a' - 'A');
				} else {
					y[i] = (char) (y[i] + 'A' - 'a');
				}
			}
		}
		System.out.println(y);
	}
}


import java.util.Scanner;

public class File1 {
	public static void main(String[] args){
		Scanner in = new Scanner(System.in);
		int MOD = 1000000007;
		int k = in.nextInt();
		long l = in.nextLong();
		long r = in.nextLong();
		long m = r-l+1;
		int n = (int)m;
		long pow[] = new long[n+1];
		pow[0] = 1;
		for(int i=1;i<=n;i++){
			pow[i] = 2*pow[i-1];
			pow[i]%=MOD;
		}
		long numPoss[] = new long[n];
		numPoss[0] = 2;
		numPoss[1] = 3;
		for(int i=2;i<n;i++){
			numPoss[i] = pow[(i+1)/2]+pow[i-(i+1)/2]-1;
			numPoss[i]%=MOD;
		}
		long ans = 0;
		for(int i=0;i<n;i++){
			if(k>numPoss[i])
				continue;
			if(k==numPoss[i]){
				ans+=1;
				ans%=MOD;
				continue;
			}
			long temp = 1;
			for(int j=0;j<k;j++){
				temp*=(numPoss[i]-j);
				temp%=MOD;
			}
			ans+=temp;
			ans%=MOD;
		}
		System.out.println(ans);
	}
}


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 A5 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	final int mod = 1000000007;

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

	void solve()
	{
		int K = ni();
		long L = nl(), R = nl();

		int[][] fif = enumFIF(K+2, mod);

		long[][] fs = new long[K+1][K+1];
		fs[0][0] = fif[1][K];
		for(int i = 0;i < K;i++){
			for(int j = 0;j <= i;j++){
				fs[i+1][j+1] += fs[i][j];
				if(fs[i+1][j+1] >= mod)fs[i+1][j+1] -= mod;
				fs[i+1][j] += fs[i][j] * (mod-i);
				fs[i+1][j] %= mod;
			}
		}

		long ret = count(R+1, fs[K], fif) - count(L, fs[K], fif);
		if(ret < 0)ret += mod;
		out.println(ret);
	}

	long count(long n, long[] fs, int[][] fif)
	{
		long ret = 0;
		for(int i = 0;i < fs.length;i++){
			ret += fpowsum(i, n, mod, fif) * fs[i];
			ret %= mod;
		}
		return ret;
	}

	long fpowsum(int K, long n, int mod, int[][] fif)
	{
		Exmod plus = Exmod.div(new Exmod(1,1),2);
		Exmod[] pluss = new Exmod[K+1];
		pluss[0] = new Exmod(1);
		for(int i = 1;i <= K;i++)pluss[i] = Exmod.mul(pluss[i-1], plus);

		Exmod minus = Exmod.div(new Exmod(1,-1),2);
		Exmod[] minuss = new Exmod[K+1];
		minuss[0] = new Exmod(1);
		for(int i = 1;i <= K;i++)minuss[i] = Exmod.mul(minuss[i-1], minus);

		Exmod ret = new Exmod(0);
		for(int i = K, sig = 1;i >= 0;i--, sig = -sig){
			Exmod ratio = Exmod.mul(pluss[i], minuss[K-i]);
			ret.add(Exmod.mul(Exmod.sumgp(ratio, n+2), C(K, i, mod, fif) * sig));
		}

		Exmod fifth = Exmod.pow(Exmod.inv(new Exmod(0, 1)), K);
		ret.mul(fifth);

		assert ret.b == 0;
		return ret.a;
	}

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

	public static class Exmod {
		public long a, b;
		public static final long E = 5;
		public static final int mod = 1000000007;

		@Override
		public String toString() {
			if(a == 0 && b == 0)return "0";
			StringBuilder ret = new StringBuilder();
			if(a != 0){
				ret.append(a);
				if(b > 0)ret.append("+");
			}
			if(b != 0)ret.append(b + "√" + E);
			return ret.toString();
		}

		public Exmod(long a) {
			this.a = a;
			this.b = 0;
			normalize();
		}

		public Exmod(long a, long b) {
			this.a = a;
			this.b = b;
			normalize();
		}

		public Exmod(Exmod e) {
			this.a = e.a;
			this.b = e.b;
			normalize();
		}

		public void normalize(){
			if(a >= mod || a < 0){
				a %= mod;
				if(a < 0)a += mod;
			}
			if(b >= mod || b < 0){
				b %= mod;
				if(b < 0)b += mod;
			}
		}

		public Exmod add(Exmod t){ a += t.a; b += t.b; normalize(); return this; }
		public Exmod sub(Exmod t){ a -= t.a; b -= t.b; normalize(); return this; }
		public Exmod mul(Exmod t){
			long na = a * t.a + b * t.b * E;
			long nb = a * t.b + b * t.a;
			a = na; b = nb; normalize(); return this;
		}
		public Exmod div(Exmod t){
			long den = t.a*t.a-E*t.b*t.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = (a*t.a - b*t.b*E) % mod * iden % mod;
			long numi = (b*t.a - a*t.b) % mod * iden % mod;
			a = numr; b = numi; normalize(); return this;
		}
		public Exmod negate(){ a = -a; b = -b; normalize(); return this; }

		public static Exmod negate(Exmod a){ return new Exmod(-a.a, -a.b);}
		public static Exmod add(Exmod a, Exmod b){return new Exmod(a.a + b.a, a.b + b.b);}
		public static Exmod sub(Exmod a, Exmod b){return new Exmod(a.a - b.a, a.b - b.b);}
		public static Exmod mul(Exmod a, Exmod b){return new Exmod(a.a * b.a + a.b * b.b * E, a.a * b.b + a.b * b.a);}
		public static Exmod div(Exmod a, Exmod b){
			long den = b.a*b.a-E*b.b*b.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = (a.a*b.a - a.b*b.b*E) % mod * iden % mod;
			if(numr < 0)numr += mod;
			long numi = (a.b*b.a - a.a*b.b) % mod * iden % mod;
			if(numi < 0)numi += mod;
			return new Exmod(numr, numi);
		}

		public static Exmod inv(Exmod a){
			long den = a.a*a.a-E*a.b*a.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = a.a * iden % mod;
			long numi = -a.b * iden % mod;
			if(numi < 0)numi += mod;
			return new Exmod(numr, numi);
		}

		// a+bx (a+bx)(c-dx) (ac-bdE)+x(bc-ad)
		// ----=------------=-----------------
		// c+dx (c+dx)(c-dx)    c^2-Ed^2

		public static Exmod mul(Exmod a, long b){return new Exmod(a.a * b, a.b * b);}
		public static Exmod div(Exmod a, long b){return mul(a, invl(b, mod));}

		public static Exmod pow(Exmod a, long n) {
			Exmod ret = new Exmod(1);
			int x = 63 - Long.numberOfLeadingZeros(n);
			for (; x >= 0; x--) {
				ret = mul(ret, ret);
				if(n<<~x<0)ret = mul(ret, a);
			}
			return ret;
		}

		public static Exmod sumgp(Exmod a, long n)
		{
			Exmod mul = new Exmod(1);
			Exmod ret = new Exmod(0);
			for(int i = 63-Long.numberOfLeadingZeros(n);i >= 0;i--){
				mul.a += 1;
				ret = mul(ret, mul);
				mul.a -= 1;
				mul = mul(mul, mul);
				if(n<<~i<0){
					ret = mul(ret, a);
					ret.a++; ret.normalize();
					mul = mul(mul, a);
				}
			}
			return ret;
		}

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

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

	private byte[] inbuf = new byte[1024];
	private 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.*;

public class A {

    long mod = (long) 1e9 + 7;

    class Num {
        final long a, b;

        public Num(long a, long b) {
            this.a = a % mod;
            this.b = b % mod;
        }

        public Num add(Num other) {
            return new Num(a + other.a, b + other.b);
        }

        public Num multiply(Num other) {
            return new Num(a * other.a + 5 * b * other.b, a * other.b + b * other.a);
        }
    }

    int k;

    long[][] coeffs;

    void prepare() {
        coeffs = new long[k + 1][k + 1];
        long[][] tmpCoeffs = new long[k + 1][k + 1];
        long factK = 1;
        coeffs[0][0] = 1;

        for (int free = 0; free < k; free++) {
            factK = factK * (free + 1) % mod;

            for (int i = 0; i <= k; i++) {
                for (int j = 0; j <= k; j++) {
                    if (coeffs[i][j] != 0) {
                        tmpCoeffs[i + 1][j] += coeffs[i][j];
                        if (tmpCoeffs[i + 1][j] >= mod) {
                            tmpCoeffs[i + 1][j] -= mod;
                        }

                        tmpCoeffs[i][j + 1] += coeffs[i][j];
                        if (tmpCoeffs[i][j + 1] >= mod) {
                            tmpCoeffs[i][j + 1] -= mod;
                        }

                        long add = coeffs[i][j] * (mod - free) % mod;
                        tmpCoeffs[i][j] += add;
                        if (tmpCoeffs[i][j] >= mod) {
                            tmpCoeffs[i][j] -= mod;
                        }
                    }
                }
            }

            for (int i = 0; i <= k; i++) {
                for (int j = 0; j <= k; j++) {
                    coeffs[i][j] = tmpCoeffs[i][j];
                    tmpCoeffs[i][j] = 0;
                }
            }
        }

        factK = inv(factK);
        for (int i = 0; i <= k; i++) {
            for (int j = 0; j <= k; j++) {
                coeffs[i][j] = coeffs[i][j] * factK % mod;
            }
        }
//        System.err.println(Arrays.deepToString(coeffs));

        pow1 = new Num[k + 1];
        powA = new Num[k + 1];
        pow2 = new Num[k + 1];
        powB = new Num[k + 1];

        pow1[0] = pow2[0] = powA[0] = powB[0] = new Num(1, 0);
        for (int i = 1; i <= k; i++) {
            pow1[i] = pow1[i - 1].multiply(PHI1);
            pow2[i] = pow2[i - 1].multiply(PHI2);
            powA[i] = powA[i - 1].multiply(A);
            powB[i] = powB[i - 1].multiply(B);
        }
    }

    long inv(long x) {
        return pow(x, mod - 2);
    }

    long pow(long a, long b) {
        long res = 1;
        while (b != 0) {
            if ((b & 1) == 1) {
                res = res * a % mod;
            }
            a = a * a % mod;
            b >>>= 1;
        }
        return res;
    }

    final Num PHI1 = new Num(inv(2), inv(2));
    final Num PHI2 = new Num(inv(2), mod - inv(2));
    final Num A = new Num(0, inv(5));
    final Num B = new Num(0, mod - inv(5));

    final Num ONE = new Num(1, 0);

    Num[] pow1, pow2, powA, powB;

    long get(long n) {
        Num result = new Num(0, 0);

        for (int i = 0; i <= k; i++) {
            for (int j = 0; j <= k; j++) {
                long coef = coeffs[i][j];
                if (coef == 0) {
                    continue;
                }

                Num cur = new Num(coef, 0).multiply(powA[i]).multiply(powB[j]);

                Num x = pow1[i].multiply(pow2[j]);
                x = geomSum(x, n + 1);

                result = result.add(cur.multiply(x));
            }
        }
        return result.a;
    }

    Num geomSum(Num x, long n) {
        if (n == 0) {
            return new Num(0, 0);
        }
        if (n % 2 == 0) {
            Num x2 = x.multiply(x);
            Num result = geomSum(x2, n / 2);
            return (ONE.add(x)).multiply(result);
        } else {
            return ONE.add(x.multiply(geomSum(x, n - 1)));
        }
    }

    public void solve() {
        k = in.nextInt();
        prepare();
        long l = in.nextLong(), r = in.nextLong();
//        for (int i = 0; i < 20; i++) {
//            Num fib = A.multiply(pow1[i]).add(B.multiply(pow2[i]));
//            System.err.println(fib.a + " " + fib.b);
//            System.err.println(get(i + 1) - get(i));
//        }
        out.println((get(r + 2) - get(l + 1) + mod) % mod);
    }

    public void run() {
        in = new FastScanner();
        out = new PrintWriter(System.out);
        solve();
        out.close();
    }

    FastScanner in;
    PrintWriter out;

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

        public FastScanner(String fileName) {
            try {
                br = new BufferedReader(new FileReader(fileName));
            } catch (FileNotFoundException e) {
            }
        }

        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) {
                }
            }
            return st.nextToken();
        }

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

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

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

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


//package bubblecup9f;
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 A5 {
	InputStream is;
	PrintWriter out;
	String INPUT = "";

	final int mod = 1000000007;

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

	void solve()
	{
		int K = ni();
		long L = nl(), R = nl();

		int[][] fif = enumFIF(K+2, mod);

		long[][] fs = new long[K+1][K+1];
		fs[0][0] = fif[1][K];
		for(int i = 0;i < K;i++){
			for(int j = 0;j <= i;j++){
				fs[i+1][j+1] += fs[i][j];
				if(fs[i+1][j+1] >= mod)fs[i+1][j+1] -= mod;
				fs[i+1][j] += fs[i][j] * (mod-i);
				fs[i+1][j] %= mod;
			}
		}

		long ret = count(R+1, fs[K], fif) - count(L, fs[K], fif);
		if(ret < 0)ret += mod;
		out.println(ret);
	}

	long count(long n, long[] fs, int[][] fif)
	{
		long ret = 0;
		for(int i = 0;i < fs.length;i++){
			ret += fpowsum(i, n, mod, fif) * fs[i];
			ret %= mod;
		}
		return ret;
	}

	long fpowsum(int K, long n, int mod, int[][] fif)
	{
		Exmod plus = Exmod.div(new Exmod(1,1),2);
		Exmod[] pluss = new Exmod[K+1];
		pluss[0] = new Exmod(1);
		for(int i = 1;i <= K;i++)pluss[i] = Exmod.mul(pluss[i-1], plus);

		Exmod minus = Exmod.div(new Exmod(1,-1),2);
		Exmod[] minuss = new Exmod[K+1];
		minuss[0] = new Exmod(1);
		for(int i = 1;i <= K;i++)minuss[i] = Exmod.mul(minuss[i-1], minus);

		Exmod ret = new Exmod(0);
		for(int i = K, sig = 1;i >= 0;i--, sig = -sig){
			Exmod ratio = Exmod.mul(pluss[i], minuss[K-i]);
			ret.add(Exmod.mul(Exmod.sumgp(ratio, n+2), C(K, i, mod, fif) * sig));
		}

		Exmod fifth = Exmod.pow(Exmod.inv(new Exmod(0, 1)), K);
		ret.mul(fifth);

		assert ret.b == 0;
		return ret.a;
	}

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

	public static class Exmod {
		public long a, b;
		public static final long E = 5;
		public static final int mod = 1000000007;

		@Override
		public String toString() {
			if(a == 0 && b == 0)return "0";
			StringBuilder ret = new StringBuilder();
			if(a != 0){
				ret.append(a);
				if(b > 0)ret.append("+");
			}
			if(b != 0)ret.append(b + "√" + E);
			return ret.toString();
		}

		public Exmod(long a) {
			this.a = a;
			this.b = 0;
			normalize();
		}

		public Exmod(long a, long b) {
			this.a = a;
			this.b = b;
			normalize();
		}

		public Exmod(Exmod e) {
			this.a = e.a;
			this.b = e.b;
			normalize();
		}

		public void normalize(){
			if(a >= mod || a < 0){
				a %= mod;
				if(a < 0)a += mod;
			}
			if(b >= mod || b < 0){
				b %= mod;
				if(b < 0)b += mod;
			}
		}

		public Exmod add(Exmod t){ a += t.a; b += t.b; normalize(); return this; }
		public Exmod sub(Exmod t){ a -= t.a; b -= t.b; normalize(); return this; }
		public Exmod mul(Exmod t){
			long na = a * t.a + b * t.b * E;
			long nb = a * t.b + b * t.a;
			a = na; b = nb; normalize(); return this;
		}
		public Exmod div(Exmod t){
			long den = t.a*t.a-E*t.b*t.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = (a*t.a - b*t.b*E) % mod * iden % mod;
			long numi = (b*t.a - a*t.b) % mod * iden % mod;
			a = numr; b = numi; normalize(); return this;
		}
		public Exmod negate(){ a = -a; b = -b; normalize(); return this; }

		public static Exmod negate(Exmod a){ return new Exmod(-a.a, -a.b);}
		public static Exmod add(Exmod a, Exmod b){return new Exmod(a.a + b.a, a.b + b.b);}
		public static Exmod sub(Exmod a, Exmod b){return new Exmod(a.a - b.a, a.b - b.b);}
		public static Exmod mul(Exmod a, Exmod b){return new Exmod(a.a * b.a + a.b * b.b * E, a.a * b.b + a.b * b.a);}
		public static Exmod div(Exmod a, Exmod b){
			long den = b.a*b.a-E*b.b*b.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = (a.a*b.a - a.b*b.b*E) % mod * iden % mod;
			if(numr < 0)numr += mod;
			long numi = (a.b*b.a - a.a*b.b) % mod * iden % mod;
			if(numi < 0)numi += mod;
			return new Exmod(numr, numi);
		}

		public static Exmod inv(Exmod a){
			long den = a.a*a.a-E*a.b*a.b;
			den %= mod; if(den < 0)den += mod;
			long iden = invl(den, mod);
			long numr = a.a * iden % mod;
			long numi = -a.b * iden % mod;
			if(numi < 0)numi += mod;
			return new Exmod(numr, numi);
		}

		// a+bx (a+bx)(c-dx) (ac-bdE)+x(bc-ad)
		// ----=------------=-----------------
		// c+dx (c+dx)(c-dx)    c^2-Ed^2

		public static Exmod mul(Exmod a, long b){return new Exmod(a.a * b, a.b * b);}
		public static Exmod div(Exmod a, long b){return mul(a, invl(b, mod));}

		public static Exmod pow(Exmod a, long n) {
			Exmod ret = new Exmod(1);
			int x = 63 - Long.numberOfLeadingZeros(n);
			for (; x >= 0; x--) {
				ret = mul(ret, ret);
				if(n<<~x<0)ret = mul(ret, a);
			}
			return ret;
		}

		public static Exmod sumgp(Exmod a, long n)
		{
			Exmod mul = new Exmod(1);
			Exmod ret = new Exmod(0);
			for(int i = 63-Long.numberOfLeadingZeros(n);i >= 0;i--){
				mul.a += 1;
				ret = mul(ret, mul);
				mul.a -= 1;
				mul = mul(mul, mul);
				if(n<<~i<0){
					ret = mul(ret, a);
					ret.a++; ret.normalize();
					mul = mul(mul, a);
				}
			}
			return ret;
		}

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

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

	private byte[] inbuf = new byte[1024];
	private 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.Arrays;
import java.util.Locale;
import java.util.StringTokenizer;
import java.util.function.Function;

public class E {
    String fileName = "E";

    public int n, m;

    public static class Event implements Comparable<Event> {
        public static final int OPEN_TYPE = 0;
        public static final int POINT_TYPE = 1;
        public static final int CLOSE_TYPE = 2;

        public int x, type;

        public Event(int x, int type) {
            this.x = x;
            this.type = type;
        }

        @Override
        public int compareTo(Event event) {
            if (Integer.compare(x, event.x) != 0)
                return Integer.compare(x, event.x);
            else return Integer.compare(type, event.type);
        }
    }

    public static final class Node {
        public int l, r;
        public int max, maxInd;

        public Node leftNode, rightNode;

        public Node(int l, int r) {
            this.l = l;
            this.r = r;
        }
    }

    public void relax(Node root) {
        if (root.leftNode.max > root.rightNode.max) {
            root.max = root.leftNode.max;
            root.maxInd = root.leftNode.maxInd;
        } else {
            root.max = root.rightNode.max;
            root.maxInd = root.rightNode.maxInd;
        }
    }

    public Node build(int l, int r, Function<Integer, Integer> getItem) {
        Node res = new Node(l, r);
        if (l == r) {
            res.max = getItem.apply(l);
            res.maxInd = l;
        } else {
            int m = (r + l) / 2;
            res.leftNode = build(l, m, getItem);
            res.rightNode = build(m + 1, r, getItem);
            relax(res);
        }
        return res;
    }

    public void set(Node root, int ind, int val) {
        if (ind < root.l || ind > root.r)
            return;
        if (root.l == root.r) {
            root.max = val;
            return;
        }
        set(root.leftNode, ind, val);
        set(root.rightNode, ind, val);
        relax(root);
    }

    public static class QueryResult {
        public int max, maxInd;

        public QueryResult(int max, int maxInd) {
            this.max = max;
            this.maxInd = maxInd;
        }

        public QueryResult(QueryResult first, QueryResult second) {
            if (first.max > second.max) {
                this.max = first.max;
                this.maxInd = first.maxInd;
            } else {
                this.max = second.max;
                this.maxInd = second.maxInd;
            }
        }
    }

    public QueryResult query(Node root, int l, int r) {
        if (r == -1)
            return new QueryResult(0, -1);
        if (r < root.l || l > root.r)
            return new QueryResult(Integer.MIN_VALUE, -1);
        if (l <= root.l && r >= root.r) {
            return new QueryResult(root.max, root.maxInd);
        }
        return new QueryResult(query(root.leftNode, l, r), query(root.rightNode, l, r));
    }

    public int[] getLens(int[] a) {
        Node root = build(0, n, ind -> 0);
        int[] len = new int[a.length];
        for (int i = 0; i < a.length; i++) {
            int curVal = a[i];
            int prevLen = query(root, 0, curVal).max;
            len[i] = prevLen + 1;
            if (query(root, curVal, curVal).max < len[i])
                set(root, curVal, len[i]);
        }
        return len;
    }

    public void solve() throws IOException {
        n = nextInt();
        m = nextInt();
        Event[] events = new Event[2 * n + m];
        for (int i = 1; i <= m; i++) {
            events[i - 1] = new Event(i, Event.POINT_TYPE);
        }
        for (int i = 0; i < n; i++) {
            int l = nextInt();
            int r = nextInt();
            events[m + 2 * i] = new Event(l, Event.OPEN_TYPE);
            events[m + 2 * i + 1] = new Event(r, Event.CLOSE_TYPE);
        }
        Arrays.sort(events);
        int[] cnt = new int[m];
        int balance = 0;
        for (int i = 0; i < events.length; i++) {
            Event curEvent = events[i];
            if (curEvent.type == Event.OPEN_TYPE) {
                balance++;
            } else if (curEvent.type == Event.CLOSE_TYPE) {
                balance--;
            } else if (curEvent.type == Event.POINT_TYPE) {
                cnt[curEvent.x - 1] = balance;
            }
        }
        int[] lenUp = getLens(cnt);
        int[] newCnt = new int[cnt.length];
        for (int i = 0; i < cnt.length; i++) {
            newCnt[i] = cnt[cnt.length - i - 1];
        }
        int[] lenDown = getLens(newCnt);
        int[] revLenDown = new int[lenDown.length];
        for (int i = 0; i < lenDown.length; i++) {
            revLenDown[i] = lenDown[lenDown.length - i - 1];
        }
        int max = 0;
        for (int i = 0; i < n; i++) {
            int cur = lenUp[i] + revLenDown[i] - 1;
            max = Math.max(max, cur);
        }
        out.print(max);
    }

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

            solve();

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

    BufferedReader br;
    StringTokenizer in;
    PrintWriter out;

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

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

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

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

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.*;

public class Main {
    ArrayList<ArrayList<Integer>> q;
    boolean[] used;

    public void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();
        int[] a = new int[m + 1];
        for (int i = 0; i < n; i++) {
            a[nextInt() - 1]++;
            a[nextInt()]--;
        }
        for (int i = 1; i < m; i++) {
            a[i] += a[i - 1];
        }
        int[] d = new int[m + 10];
        Arrays.fill(d, Integer.MAX_VALUE);
        int k = 0;
        int[] v1 = new int[m + 1];
        int[] v2 = new int[m + 1];
        for (int i = 0; i < m; i++) {
            int l = 0;
            int r = m;
            while (r - l > 1) {
                int m1 = (r + l) / 2;
                if (d[m1] > a[i]) {
                    r = m1;
                } else {
                    l = m1;
                }
            }
            if (d[l] <= a[i]) {
                l++;
            }
            if (d[l] == Integer.MAX_VALUE){
                k++;
            }
            d[l] = a[i];
            v1[i] = k;
        }
        k = 0;
        int max = 0;
        for (int i = m - 1; i >= 0; i--) {
            int l = 0;
            int r = m + 2;
            while (r - l > 1) {
                int m1 = (r + l) / 2;
                if (d[m1] > a[i]) {
                    r = m1;
                } else {
                    l = m1;
                }
            }
            if (d[l] <= a[i]) {
                l++;
            }
            if (d[l] == Integer.MAX_VALUE){
                k++;
            }
            d[l] = a[i];
            v2[i] = k;
            max = Math.max(max,v1[i] + v2[i + 1]);
        }
        out.print(max);
    }

    BufferedReader br;
    StringTokenizer sc;
    PrintWriter out;

    String nextToken() throws IOException {
        while (sc == null || !sc.hasMoreTokens()) {
            try {
                sc = new StringTokenizer(br.readLine());
            } catch (Exception e) {
                sc = null;
            }
        }
        return sc.nextToken();
    }

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

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

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

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

    public void run() throws IOException {
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            out = new PrintWriter(System.out);
            solve();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.lang.reflect.Array;
import java.util.*;

public class Main {
    ArrayList<ArrayList<Integer>> q;
    boolean[] used;

    public void solve() throws IOException {
        int n = nextInt();
        int m = nextInt();
        int[] a = new int[m + 1];
        for (int i = 0; i < n; i++) {
            a[nextInt() - 1]++;
            a[nextInt()]--;
        }
        for (int i = 1; i < m; i++) {
            a[i] += a[i - 1];
        }
        int[] d = new int[m + 1];
        Arrays.fill(d, Integer.MAX_VALUE);
        int k = 0;
        int[] v1 = new int[m + 2];
        int[] v2 = new int[m + 2];
        for (int i = 0; i < m; i++) {
            int l = 0;
            int r = m;
            while (r - l > 1) {
                int m1 = (r + l) / 2;
                if (d[m1] > a[i]) {
                    r = m1;
                } else {
                    l = m1;
                }
            }
            if (d[l] <= a[i]) {
                l++;
            }
            if (d[l] == Integer.MAX_VALUE){
                k++;
            }
            d[l] = a[i];
            v1[i] = k;
        }
        k = 0;
        int max = 0;
        Arrays.fill(d,Integer.MAX_VALUE);
        for (int i = m - 1; i >= 0; i--) {
            int l = 0;
            int r = m;
            while (r - l > 1) {
                int m1 = (r + l) / 2;
                if (d[m1] > a[i]) {
                    r = m1;
                } else {
                    l = m1;
                }
            }
            if (d[l] <= a[i]) {
                l++;
            }
            if (d[l] == Integer.MAX_VALUE){
                k++;
            }
            d[l] = a[i];
            v2[i] = k;
            max = Math.max(max,v1[i] + v2[i + 1]);
        }
        max = Math.max(max,v2[0]);
        out.print(max);
    }

    BufferedReader br;
    StringTokenizer sc;
    PrintWriter out;

    String nextToken() throws IOException {
        while (sc == null || !sc.hasMoreTokens()) {
            try {
                sc = new StringTokenizer(br.readLine());
            } catch (Exception e) {
                sc = null;
            }
        }
        return sc.nextToken();
    }

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

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

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

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

    public void run() throws IOException {
        try {
            br = new BufferedReader(new InputStreamReader(System.in));
            out = new PrintWriter(System.out);
            solve();
            out.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }
}