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

/**
 * Created by dalt on 2018/3/14.
 */
public class CF939F {
    public static final int INF = (int) 1e8;
    public static BlockReader input;
    public static PrintStream output;

    public static void main(String[] args) throws FileNotFoundException {
        if (System.getProperty("ONLINE_JUDGE") == null) {
            input = new BlockReader(new FileInputStream("D:\\DataBase\\TESTCASE\\codeforces\\CF939F.in"));
            output = System.out;
        } else {
            input = new BlockReader(System.in);
            output = new PrintStream(new BufferedOutputStream(System.out), false);
        }

        solve();

        output.flush();
    }

    public static void solve() {
        int n = input.nextInteger();
        int k = input.nextInteger();

        int[][] intervals = new int[k + 2][2];
        for (int i = 1; i <= k; i++) {
            intervals[i][0] = input.nextInteger();
            intervals[i][1] = input.nextInteger();
        }
        intervals[k + 1][0] = 2 * n;
        intervals[k + 1][1] = 2 * n;

        k++;

        Node[] loop = new Node[2];
        loop[0] = Node.build(0, n);
        loop[1] = Node.build(0, n);

        int[] data = new int[n + 1];

        for (int i = 1; i <= k; i++) {
            Node curDp = loop[i & 1];

            Node lastDp = loop[(i - 1) & 1];

            int[] interval = intervals[i];
            int intervalLength = interval[1] - interval[0];
            int middleLength = interval[0] - intervals[i - 1][1];

            Node.toArray(0, n, data, lastDp);
            System.arraycopy(data, 0, data, intervalLength + middleLength, n + 1 - (intervalLength + middleLength));
            Arrays.fill(data, 0, intervalLength + middleLength, INF);

            //No flip
/*            for (int j = intervalLength + middleLength; j <= n; j++) {
                int lastFryTotalTime = j - intervalLength - middleLength;
                int minNeedTime = Node.query(lastFryTotalTime, lastFryTotalTime, 0, n, lastDp);
                Node.update(j, 0, n, minNeedTime, curDp);
            }*/

            int minX = interval[1] - middleLength - intervalLength;
            int maxX = interval[1] - middleLength;
            for (int j = 0; j <= n; j++) {
                //Flip once
                int minNeedTime = Node.query(minX - j, maxX - j, 0, n, lastDp);
                data[j] = Math.min(data[j], minNeedTime + 1);
               // Node.update(j, 0, n, minNeedTime + 1, curDp);
            }

            for (int j = 0; j <= n; j++) {
                //Flip twice
                int minNeedTime = Node.query(interval[1] - intervalLength, interval[1], 0, n, lastDp);
                //Node.update(j, 0, n, minNeedTime + 2, curDp);
                data[j] = Math.min(data[j], minNeedTime + 2);
            }

            Node.fromArray(0, n, data, curDp);
        }

        int minFlipTime = Node.query(n, n, 0, n, loop[k & 1]);

        if (minFlipTime < INF) {
            output.println("Full");
            output.println(minFlipTime);
        } else {
            output.println("Hungry");
        }
    }

    public static class Node {
        Node left;
        Node right;
        int batchSetValue;
        boolean dirty;
        int min;

        public static void setValue(int f, int t, int l, int r, int val, Node node) {
            if (f > r || t < l) {
                return;
            }
            if (f <= l && t >= r) {
                node.setValue(val);
                return;
            }

            node.pushDown();
            int m = (l + r) >> 1;
            setValue(f, t, l, m, val, node.left);
            setValue(f, t, m + 1, r, val, node.right);

            node.pushUp();
        }

        public static Node build(int l, int r) {
            Node node = new Node();
            if (l != r) {
                int m = (l + r) >> 1;
                node.left = build(l, m);
                node.right = build(m + 1, r);
            }
            return node;
        }

        public static int query(int f, int t, int l, int r, Node node) {
            if (f > r || t < l) {
                return INF;
            }
            if (f <= l && r <= t) {
                return node.min;
            }
            node.pushDown();
            int m = (l + r) >> 1;
            return Math.min(query(f, t, l, m, node.left), query(f, t, m + 1, r, node.right));
        }

        public static void update(int i, int l, int r, int val, Node node) {
            if (i > r || i < l) {
                return;
            }
            if (i <= l && i >= r) {
                node.min = Math.min(node.min, val);
                return;
            }

            node.pushDown();
            int m = (l + r) >> 1;
            update(i, l, m, val, node.left);
            update(i, m + 1, r, val, node.right);

            node.pushUp();
        }

        public static void toArray(int l, int r, int[] data, Node node) {
            if (l == r) {
                data[l] = node.min;
                return;
            }
            node.pushDown();
            int m = (l + r) >> 1;
            toArray(l, m, data, node.left);
            toArray(m + 1, r, data, node.right);
        }

        public static void fromArray(int l, int r, int[] data, Node node) {
            if (l == r) {
                node.min = data[l];
                return;
            }

            node.dirty = false;
            int m = (l + r) >> 1;
            fromArray(l, m, data, node.left);
            fromArray(m + 1, r, data, node.right);
            node.pushUp();
        }

        public void pushUp() {
            this.min = Math.min(left.min, right.min);
        }

        public void setValue(int val) {
            this.min = val;
            this.batchSetValue = val;
            this.dirty = true;
        }

        public void pushDown() {
            if (dirty) {
                left.setValue(batchSetValue);
                right.setValue(batchSetValue);
                dirty = false;
            }
        }

        @Override
        public String toString() {
            int t = 100;
            int[] data = new int[t + 1];
            for (int i = 0; i <= t; i++) {
                data[i] = query(i, i, 0, t, this);
            }
            return Arrays.toString(data);
        }
    }

    public static class BlockReader {
        static final int EOF = -1;
        InputStream is;
        byte[] dBuf;
        int dPos, dSize, next;
        StringBuilder builder = new StringBuilder();

        public BlockReader(InputStream is) {
            this(is, 4096);
        }

        public BlockReader(InputStream is, int bufSize) {
            this.is = is;
            dBuf = new byte[bufSize];
            next = nextByte();
        }

        public int nextByte() {
            while (dPos >= dSize) {
                if (dSize == -1) {
                    return EOF;
                }
                dPos = 0;
                try {
                    dSize = is.read(dBuf);
                } catch (Exception e) {
                }
            }
            return dBuf[dPos++];
        }

        public String nextBlock() {
            builder.setLength(0);
            skipBlank();
            while (next != EOF && !Character.isWhitespace(next)) {
                builder.append((char) next);
                next = nextByte();
            }
            return builder.toString();
        }

        public void skipBlank() {
            while (Character.isWhitespace(next)) {
                next = nextByte();
            }
        }

        public int nextInteger() {
            skipBlank();
            int ret = 0;
            boolean rev = false;
            if (next == '+' || next == '-') {
                rev = next == '-';
                next = nextByte();
            }
            while (next >= '0' && next <= '9') {
                ret = (ret << 3) + (ret << 1) + next - '0';
                next = nextByte();
            }
            return rev ? -ret : ret;
        }

        public int nextBlock(char[] data, int offset) {
            skipBlank();
            int index = offset;
            int bound = data.length;
            while (next != EOF && index < bound && !Character.isWhitespace(next)) {
                data[index++] = (char) next;
                next = nextByte();
            }
            return index - offset;
        }

        public boolean hasMore() {
            skipBlank();
            return next != EOF;
        }
    }
}


/**
 * Created by IntelliJ IDEA.
 * User: mac
 * Date: 11-12-24
 * Time: 下午7:56
 * To change this template use File | Settings | File Templates.
 */

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

public class e {

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

    void run() {
        try {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
            writer = new PrintWriter(System.out);
            solve();
            reader.close();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    String nextToken() throws IOException {
        while (tokenizer == null || !tokenizer.hasMoreTokens())
            tokenizer = new StringTokenizer(reader.readLine());
        return tokenizer.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());
    }

    void solve() throws IOException {
        String input = nextToken();
        int n = input.length();
        int[] what = new int[n];
        for (int i = 0; i < n; i++) {
            what[i] = input.charAt(i) - 'a';
        }

        int k = nextInt(), L = nextInt(), R = nextInt();
        int[] id = new int[k], l = new int[k], r = new int[k];

        int[] cnt = new int[n];

        for (int i = 0; i < k; i++) {
            id[i] = nextToken().charAt(0) - 'a';
            l[i] = nextInt();
            r[i] = nextInt();
        }

        int[] atL = new int[k], atR = new int[k];//[l,r)
        long ans = 0;

        @SuppressWarnings({"unchecked"})
        List<Integer>[] by = new List[26];
        for (int i = 0; i < 26; i++) {
            by[i] = new ArrayList<Integer>();
        }

        for (int i = 0; i < n; i++) {
            by[what[i]].add(i);
        }

        for (int i = 0; i < k; i++) {
            if (by[id[i]].size() < l[i]) {
                atL[i] = atR[i] = n;
            } else {
                if (l[i] == 0) {
                    atL[i] = 0;
                } else {
                    atL[i] = by[id[i]].get(l[i] - 1);
                }
                if (by[id[i]].size() <= r[i]) {
                    atR[i] = n;
                } else {
                    atR[i] = by[id[i]].get(r[i]);
                }
            }
        }

        for (int i = 0; i < k; i++) {
            for (int j = atL[i]; j < atR[i]; j++) {
                cnt[j]++;
            }
        }
        int curCount = 0;
        for (int i = 0; i < n; i++) {
            if (cnt[i] >= L && cnt[i] <= R)
                ++curCount;
        }

        for (int i = 0; i < n; i++) {
            int me = what[i];
            ans += curCount;

            for (int j = 0; j < k; j++) {
                if (id[j] == me) {
                    int x = atL[j];
                    while (x < n) {
                        if (cnt[x] >= L && cnt[x] <= R) {
                            --curCount;
                        }
                        cnt[x]--;
                        if (cnt[x] >= L && cnt[x] <= R) {
                            ++curCount;
                        }
                        ++x;
                        if (x == n || what[x] == me)
                            break;
                    }
                    atL[j] = x;

                    x = atR[j];
                    while (x < n) {
                        if (cnt[x] >= L && cnt[x] <= R) {
                            --curCount;
                        }
                        cnt[x]++;
                        if (cnt[x] >= L && cnt[x] <= R) {
                            ++curCount;
                        }
                        ++x;
                        if (x == n || what[x] == me)
                            break;
                    }
                    atR[j] = x;
                }
            }

            if (cnt[i] >= L && cnt[i] <= R)
                --curCount;
        }

        writer.println(ans);
    }

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


/**
 * Created by IntelliJ IDEA.
 * User: mac
 * Date: 11-12-24
 * Time: 下午7:56
 * To change this template use File | Settings | File Templates.
 */

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

public class e {

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

    void run() {
        try {
            reader = new BufferedReader(new InputStreamReader(System.in));
            tokenizer = null;
            writer = new PrintWriter(System.out);
            solve();
            reader.close();
            writer.close();
        } catch (Exception e) {
            e.printStackTrace();
            System.exit(1);
        }
    }

    String nextToken() throws IOException {
        while (tokenizer == null || !tokenizer.hasMoreTokens())
            tokenizer = new StringTokenizer(reader.readLine());
        return tokenizer.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());
    }

    void solve() throws IOException {
        String input = nextToken();
        int n = input.length();
        int[] what = new int[n];
        for (int i = 0; i < n; i++) {
            what[i] = input.charAt(i) - 'a';
        }

        int k = nextInt(), L = nextInt(), R = nextInt();
        int[] id = new int[k], l = new int[k], r = new int[k];

        int[] cnt = new int[n];

        for (int i = 0; i < k; i++) {
            id[i] = nextToken().charAt(0) - 'a';
            l[i] = nextInt();
            r[i] = nextInt();
        }

        int[] atL = new int[k], atR = new int[k];//[l,r)
        long ans = 0;

        @SuppressWarnings({"unchecked"})
        List<Integer>[] by = new List[26];
        for (int i = 0; i < 26; i++) {
            by[i] = new ArrayList<Integer>();
        }

        for (int i = 0; i < n; i++) {
            by[what[i]].add(i);
        }

        for (int i = 0; i < k; i++) {
            if (by[id[i]].size() < l[i]) {
                atL[i] = atR[i] = n;
            } else {
                if (l[i] == 0) {
                    atL[i] = 0;
                } else {
                    atL[i] = by[id[i]].get(l[i] - 1);
                }
                if (by[id[i]].size() <= r[i]) {
                    atR[i] = n;
                } else {
                    atR[i] = by[id[i]].get(r[i]);
                }
            }
        }

        for (int i = 0; i < k; i++) {
            for (int j = atL[i]; j < atR[i]; j++) {
                cnt[j]++;
            }
        }
        int curCount = 0;
        for (int i = 0; i < n; i++) {
            if (cnt[i] >= L && cnt[i] <= R)
                ++curCount;
        }

        for (int i = 0; i < n; i++) {
            int me = what[i];
            ans += curCount;

            for (int j = 0; j < k; j++) {
                if (id[j] == me) {
                    int x = atL[j];
                    while (x < n) {
                        if (x >= i) {
                            if (cnt[x] >= L && cnt[x] <= R) {
                                --curCount;
                            }
                            cnt[x]--;
                            if (cnt[x] >= L && cnt[x] <= R) {
                                ++curCount;
                            }
                        }
                        ++x;
                        if (x == n || what[x] == me)
                            break;
                    }
                    atL[j] = x;

                    x = atR[j];
                    while (x < n) {
                        if (x >= i) {
                            if (cnt[x] >= L && cnt[x] <= R) {
                                --curCount;
                            }
                            cnt[x]++;
                            if (cnt[x] >= L && cnt[x] <= R) {
                                ++curCount;
                            }
                            ++x;
                        }
                        if (x == n || what[x] == me)
                            break;
                    }
                    atR[j] = x;
                }
            }

            if (cnt[i] >= L && cnt[i] <= R)
                --curCount;
        }

        writer.println(ans);
    }

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


//package school3;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Scanner;

public class F5 {
	Scanner in;
	PrintWriter out;
//	String INPUT = "100000 4";
//	String INPUT = "2 100000";
	String INPUT = "";

	int[] dec(int n, int m)
	{
		if(n <= m){
			return new int[]{n, 0};
		}else if(n <= 2 * m){
			return new int[]{n - m, n - m};
		}else{
			return new int[]{n - 2 * m - 1, m};
		}
	}

	int enc(int x, int y, int m)
	{
		if(y == 0){
			return x;
		}else if(x == y){
			return x + m;
		}else{
			return x + 2 * m + 1;
		}
	}

	void solve()
	{
		int m = ni();
		int n = ni();
		if(m == 2 && n == 2){
			out.println(3);
			return;
		}
		if(m <= 0){
			out.println(1);
			return;
		}
		if(n <= 1){
			out.println(-1);
			return;
		}

//		for(int i = 0;i <= 3 * m;i++){
//			int[] co = dec(i, m);
//			tr(co);
//			if(enc(co[0], co[1], m) != i){
//				tr("out!",i);
//			}
//		}

//		int[] co = {0, 0};
//		{
//			if(co[1] == 0){
//				int inf = co[0] + 1;
//				int sup = Math.min(m, co[0] + n);
//				if(inf <= sup){
//					tr(inf, 0, sup, 0, enc(inf, 0, m), enc(sup, 0, m));
//				}
//			}
//		}
//		{
//			int inf = Math.max(co[0], co[1]);
//			if(co[0] == co[1])inf++;
//			int sup = Math.min(m, (n + co[0] + co[1]) / 2);
//
//			if(inf <= sup){
//				tr(inf, inf, sup, sup, enc(inf, inf, m), enc(sup, sup, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == m)inf++;
//			int sup = Math.min(m - 1, co[0] + n - m + co[1]);
//			if(inf <= sup){
//				tr(inf, m, sup, m, enc(inf, m, m), enc(sup, m, m));
//			}
//		}
//		{
//			if(co[1] == m){
//				int inf = co[0] - 1;
//				int sup = Math.max(0, co[0] - n);
//				if(sup <= inf){
//					tr(sup, m, inf, m, enc(sup, m, m), enc(inf, m, m));
//				}
//			}
//		}
//		{
//			int inf = Math.min(co[0], co[1]);
//			if(co[0] == co[1])inf--;
//			int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);
//
////			if(sup == 0)sup++;
//			if(sup <= inf){
//				tr(sup, sup, inf, inf, enc(sup, sup, m), enc(inf, inf, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == 0)inf--;
//			int sup = Math.max(0, co[0] - n + co[1]);
//			if(sup <= inf){
//				tr(sup, 0, inf, 0, enc(sup, 0, m), enc(inf, 0, m));
//			}
//		}

		if(n <= Math.sqrt(Math.sqrt(m))){
			solveH(m, n);
		}else{
			solveB(m, n);
		}
	}

	void solveB(int m, int n){
			// (a, 0), (a, a), (a, m)
			BitSet visitedo = new BitSet();
			BitSet visitedh = new BitSet();
			BitSet q = new BitSet();
			q.set(0);
			boolean iso = true;
			int step = 0;

			while(!q.isEmpty()){
				if(!iso && q.get(2 * m))break;
//				tr(step, q);
				BitSet nq = new BitSet();
				if(iso){
					visitedh.or(q);
				}else{
					visitedo.or(q);
				}
				for(int cur = q.nextSetBit(0);cur != -1;cur = q.nextSetBit(cur+1)){
					int[] co = dec(cur, m);
					if(iso){
						{
							if(co[1] == 0){
								int inf = co[0] + 1;
								int sup = Math.min(m, co[0] + n);
								if(inf <= sup){
									nq.set(enc(inf, 0, m), enc(sup, 0, m) + 1);
								}
							}
						}
						{
							int inf = Math.max(co[0], co[1]);
							if(co[0] == co[1])inf++;
							int sup = Math.min(m, (n + co[0] + co[1]) / 2);

							if(inf <= sup){
								nq.set(enc(inf, inf, m), enc(sup, sup, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == m)inf++;
							int sup = Math.min(m - 1, co[0] + n - m + co[1]);
							if(inf <= sup){
								nq.set(enc(inf, m, m), enc(sup, m, m) + 1);
							}
						}
					}else{
						{
							if(co[1] == m){
								int inf = co[0] - 1;
								int sup = Math.max(0, co[0] - n);
								if(sup <= inf){
									nq.set(enc(sup, m, m), enc(inf, m, m) + 1);
								}
							}
						}
						{
							int inf = Math.min(co[0], co[1]);
							if(co[0] == co[1])inf--;
							int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//							if(sup == 0)sup++;
							if(sup <= inf){
								nq.set(enc(sup, sup, m), enc(inf, inf, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == 0)inf--;
							int sup = Math.max(0, co[0] - n + co[1]);
							if(sup <= inf){
								nq.set(enc(sup, 0, m), enc(inf, 0, m) + 1);
							}
						}
					}
				}
				if(iso){
					nq.andNot(visitedo);
				}else{
					nq.andNot(visitedh);
				}
				q = nq;
				step++;
				iso = !iso;
			}
			if(q.isEmpty()){
				out.println(-1);
			}else{
				out.println(step);
			}
	}

	void solveH(int m, int n){

		// (a, 0), (a, a), (a, m)
		HashSet<Integer> visitedo = new HashSet<Integer>();
		HashSet<Integer> visitedh = new HashSet<Integer>();
		HashSet<Integer> q = new HashSet<Integer>();
		q.add(0);
		boolean iso = true;
		int step = 0;

		while(!q.isEmpty()){
			if(!iso && q.contains(2 * m))break;
//			tr(step, q);
			HashSet<Integer> nq = new HashSet<Integer>();
			if(iso){
				visitedh.addAll(q);
			}else{
				visitedo.addAll(q);
			}
			for(int cur : q){
				int[] co = dec(cur, m);
				if(iso){
					{
						if(co[1] == 0){
							int inf = co[0] + 1;
							int sup = Math.min(m, co[0] + n);
							if(inf <= sup){
								for(int i = enc(inf, 0, m);i <= enc(sup, 0, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.max(co[0], co[1]);
						if(co[0] == co[1])inf++;
						int sup = Math.min(m, (n + co[0] + co[1]) / 2);

						if(inf == 0)inf = 1;
						if(inf <= sup){
							for(int i = enc(inf, inf, m);i <= enc(sup, sup, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == m)inf++;
						int sup = Math.min(m - 1, co[0] + n - m + co[1]);
						if(inf <= sup){
							for(int i = enc(inf, m, m);i <= enc(sup, m, m);i++){
								nq.add(i);
							}
						}
					}
				}else{
					{
						if(co[1] == m){
							int inf = co[0] - 1;
							int sup = Math.max(0, co[0] - n);
							if(sup <= inf){
								for(int i = enc(sup, m, m);i <= enc(inf, m, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.min(co[0], co[1]);
						if(co[0] == co[1])inf--;
						int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//						if(sup == 0)sup++;
						if(sup <= inf){
							for(int i = enc(sup, sup, m);i <= enc(inf, inf, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == 0)inf--;
						int sup = Math.max(0, co[0] - n + co[1]);
						if(sup <= inf){
							for(int i = enc(sup, 0, m);i <= enc(inf, 0, m);i++){
								nq.add(i);
							}
						}
					}
				}
			}
			if(iso){
				nq.removeAll(visitedo);
			}else{
				nq.removeAll(visitedh);
			}
			q = nq;
			step++;
			iso = !iso;
		}
		if(q.isEmpty()){
			out.println(-1);
		}else{
			out.println(step);
		}
	}

	void run() throws Exception
	{
		in = INPUT.isEmpty() ? new Scanner(System.in) : new Scanner(INPUT);
		out = new PrintWriter(System.out);

		out.println(INPUT);
		solve();
		out.flush();
	}

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

	int ni() { return Integer.parseInt(in.next()); }
	void tr(Object... o) { if(INPUT.length() != 0)System.out.println(o.length > 1 || o[0].getClass().isArray() ? Arrays.deepToString(o) : o[0]); }
}


//package school3;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Scanner;

public class F5 {
	Scanner in;
	PrintWriter out;
//	String INPUT = "100000 4";
//	String INPUT = "2 100000";
	String INPUT = "";

	int[] dec(int n, int m)
	{
		if(n <= m){
			return new int[]{n, 0};
		}else if(n <= 2 * m){
			return new int[]{n - m, n - m};
		}else{
			return new int[]{n - 2 * m - 1, m};
		}
	}

	int enc(int x, int y, int m)
	{
		if(y == 0){
			return x;
		}else if(x == y){
			return x + m;
		}else{
			return x + 2 * m + 1;
		}
	}

	void solve()
	{
		int m = ni();
		int n = ni();
		if(m == 2 && n == 2){
			throw new Error();
//			return;
		}
		if(m <= 0){
			out.println(1);
			return;
		}
		if(n <= 1){
			out.println(-1);
			return;
		}

//		for(int i = 0;i <= 3 * m;i++){
//			int[] co = dec(i, m);
//			tr(co);
//			if(enc(co[0], co[1], m) != i){
//				tr("out!",i);
//			}
//		}

//		int[] co = {0, 0};
//		{
//			if(co[1] == 0){
//				int inf = co[0] + 1;
//				int sup = Math.min(m, co[0] + n);
//				if(inf <= sup){
//					tr(inf, 0, sup, 0, enc(inf, 0, m), enc(sup, 0, m));
//				}
//			}
//		}
//		{
//			int inf = Math.max(co[0], co[1]);
//			if(co[0] == co[1])inf++;
//			int sup = Math.min(m, (n + co[0] + co[1]) / 2);
//
//			if(inf <= sup){
//				tr(inf, inf, sup, sup, enc(inf, inf, m), enc(sup, sup, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == m)inf++;
//			int sup = Math.min(m - 1, co[0] + n - m + co[1]);
//			if(inf <= sup){
//				tr(inf, m, sup, m, enc(inf, m, m), enc(sup, m, m));
//			}
//		}
//		{
//			if(co[1] == m){
//				int inf = co[0] - 1;
//				int sup = Math.max(0, co[0] - n);
//				if(sup <= inf){
//					tr(sup, m, inf, m, enc(sup, m, m), enc(inf, m, m));
//				}
//			}
//		}
//		{
//			int inf = Math.min(co[0], co[1]);
//			if(co[0] == co[1])inf--;
//			int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);
//
////			if(sup == 0)sup++;
//			if(sup <= inf){
//				tr(sup, sup, inf, inf, enc(sup, sup, m), enc(inf, inf, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == 0)inf--;
//			int sup = Math.max(0, co[0] - n + co[1]);
//			if(sup <= inf){
//				tr(sup, 0, inf, 0, enc(sup, 0, m), enc(inf, 0, m));
//			}
//		}

		if(n <= Math.sqrt(Math.sqrt(m))){
			solveH(m, n);
		}else{
			solveB(m, n);
		}
	}

	void solveB(int m, int n){
			// (a, 0), (a, a), (a, m)
			BitSet visitedo = new BitSet();
			BitSet visitedh = new BitSet();
			BitSet q = new BitSet();
			q.set(0);
			boolean iso = true;
			int step = 0;

			while(!q.isEmpty()){
				if(!iso && q.get(2 * m))break;
//				tr(step, q);
				BitSet nq = new BitSet();
				if(iso){
					visitedh.or(q);
				}else{
					visitedo.or(q);
				}
				for(int cur = q.nextSetBit(0);cur != -1;cur = q.nextSetBit(cur+1)){
					int[] co = dec(cur, m);
					if(iso){
						{
							if(co[1] == 0){
								int inf = co[0] + 1;
								int sup = Math.min(m, co[0] + n);
								if(inf <= sup){
									nq.set(enc(inf, 0, m), enc(sup, 0, m) + 1);
								}
							}
						}
						{
							int inf = Math.max(co[0], co[1]);
							if(co[0] == co[1])inf++;
							int sup = Math.min(m, (n + co[0] + co[1]) / 2);

							if(inf <= sup){
								nq.set(enc(inf, inf, m), enc(sup, sup, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == m)inf++;
							int sup = Math.min(m - 1, co[0] + n - m + co[1]);
							if(inf <= sup){
								nq.set(enc(inf, m, m), enc(sup, m, m) + 1);
							}
						}
					}else{
						{
							if(co[1] == m){
								int inf = co[0] - 1;
								int sup = Math.max(0, co[0] - n);
								if(sup <= inf){
									nq.set(enc(sup, m, m), enc(inf, m, m) + 1);
								}
							}
						}
						{
							int inf = Math.min(co[0], co[1]);
							if(co[0] == co[1])inf--;
							int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//							if(sup == 0)sup++;
							if(sup <= inf){
								nq.set(enc(sup, sup, m), enc(inf, inf, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == 0)inf--;
							int sup = Math.max(0, co[0] - n + co[1]);
							if(sup <= inf){
								nq.set(enc(sup, 0, m), enc(inf, 0, m) + 1);
							}
						}
					}
				}
				if(iso){
					nq.andNot(visitedo);
				}else{
					nq.andNot(visitedh);
				}
				q = nq;
				step++;
				iso = !iso;
			}
			if(q.isEmpty()){
				out.println(-1);
			}else{
				out.println(step);
			}
	}

	void solveH(int m, int n){

		// (a, 0), (a, a), (a, m)
		HashSet<Integer> visitedo = new HashSet<Integer>();
		HashSet<Integer> visitedh = new HashSet<Integer>();
		HashSet<Integer> q = new HashSet<Integer>();
		q.add(0);
		boolean iso = true;
		int step = 0;

		while(!q.isEmpty()){
			if(!iso && q.contains(2 * m))break;
//			tr(step, q);
			HashSet<Integer> nq = new HashSet<Integer>();
			if(iso){
				visitedh.addAll(q);
			}else{
				visitedo.addAll(q);
			}
			for(int cur : q){
				int[] co = dec(cur, m);
				if(iso){
					{
						if(co[1] == 0){
							int inf = co[0] + 1;
							int sup = Math.min(m, co[0] + n);
							if(inf <= sup){
								for(int i = enc(inf, 0, m);i <= enc(sup, 0, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.max(co[0], co[1]);
						if(co[0] == co[1])inf++;
						int sup = Math.min(m, (n + co[0] + co[1]) / 2);

						if(inf == 0)inf = 1;
						if(inf <= sup){
							for(int i = enc(inf, inf, m);i <= enc(sup, sup, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == m)inf++;
						int sup = Math.min(m - 1, co[0] + n - m + co[1]);
						if(inf <= sup){
							for(int i = enc(inf, m, m);i <= enc(sup, m, m);i++){
								nq.add(i);
							}
						}
					}
				}else{
					{
						if(co[1] == m){
							int inf = co[0] - 1;
							int sup = Math.max(0, co[0] - n);
							if(sup <= inf){
								for(int i = enc(sup, m, m);i <= enc(inf, m, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.min(co[0], co[1]);
						if(co[0] == co[1])inf--;
						int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//						if(sup == 0)sup++;
						if(sup <= inf){
							for(int i = enc(sup, sup, m);i <= enc(inf, inf, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == 0)inf--;
						int sup = Math.max(0, co[0] - n + co[1]);
						if(sup <= inf){
							for(int i = enc(sup, 0, m);i <= enc(inf, 0, m);i++){
								nq.add(i);
							}
						}
					}
				}
			}
			if(iso){
				nq.removeAll(visitedo);
			}else{
				nq.removeAll(visitedh);
			}
			q = nq;
			step++;
			iso = !iso;
		}
		if(q.isEmpty()){
			out.println(-1);
		}else{
			out.println(step);
		}
	}

	void run() throws Exception
	{
		in = INPUT.isEmpty() ? new Scanner(System.in) : new Scanner(INPUT);
		out = new PrintWriter(System.out);

		out.println(INPUT);
		solve();
		out.flush();
	}

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

	int ni() { return Integer.parseInt(in.next()); }
	void tr(Object... o) { if(INPUT.length() != 0)System.out.println(o.length > 1 || o[0].getClass().isArray() ? Arrays.deepToString(o) : o[0]); }
}


package ACM;

import java.util.Scanner;

public class CF45F {

	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int m = sc.nextInt();
		int n = sc.nextInt();
		sc.close();
		int ans=0;
		boolean f = false;
		if(n==1) {
			P(-1);
			return ;
		}
		if(n==2 && m==3||n==3 && m==5) {
			P(11);
			return ;
		}
		for(;;)
		{
			if(n>=m+m) {
				P(ans+1);
				return ;
			}
			else if(n>=m)
			{
				P(ans+(n==m?5:3));
				return ;
			}
			else if(!f) {
				m-=n-2;
				ans=4;
				f=true;
			}
			else
			{
				if(n/2==1)
				{
					P(-1);
					return ;
				}
				m-=n/2-1;
				ans+=2;
			}
		}
	}
	public static void P(int x)
	{
		System.out.println(x);
	}
}


//package school3;

import java.io.PrintWriter;
import java.util.Arrays;
import java.util.BitSet;
import java.util.HashSet;
import java.util.Scanner;

public class F5 {
	Scanner in;
	PrintWriter out;
//	String INPUT = "100000 4";
//	String INPUT = "2 100000";
	String INPUT = "";

	int[] dec(int n, int m)
	{
		if(n <= m){
			return new int[]{n, 0};
		}else if(n <= 2 * m){
			return new int[]{n - m, n - m};
		}else{
			return new int[]{n - 2 * m - 1, m};
		}
	}

	int enc(int x, int y, int m)
	{
		if(y == 0){
			return x;
		}else if(x == y){
			return x + m;
		}else{
			return x + 2 * m + 1;
		}
	}

	void solve()
	{
		int m = ni();
		int n = ni();
		if(m == 2 && n == 2){
			throw new Error();
			return;
		}
		if(m <= 0){
			out.println(1);
			return;
		}
		if(n <= 1){
			out.println(-1);
			return;
		}

//		for(int i = 0;i <= 3 * m;i++){
//			int[] co = dec(i, m);
//			tr(co);
//			if(enc(co[0], co[1], m) != i){
//				tr("out!",i);
//			}
//		}

//		int[] co = {0, 0};
//		{
//			if(co[1] == 0){
//				int inf = co[0] + 1;
//				int sup = Math.min(m, co[0] + n);
//				if(inf <= sup){
//					tr(inf, 0, sup, 0, enc(inf, 0, m), enc(sup, 0, m));
//				}
//			}
//		}
//		{
//			int inf = Math.max(co[0], co[1]);
//			if(co[0] == co[1])inf++;
//			int sup = Math.min(m, (n + co[0] + co[1]) / 2);
//
//			if(inf <= sup){
//				tr(inf, inf, sup, sup, enc(inf, inf, m), enc(sup, sup, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == m)inf++;
//			int sup = Math.min(m - 1, co[0] + n - m + co[1]);
//			if(inf <= sup){
//				tr(inf, m, sup, m, enc(inf, m, m), enc(sup, m, m));
//			}
//		}
//		{
//			if(co[1] == m){
//				int inf = co[0] - 1;
//				int sup = Math.max(0, co[0] - n);
//				if(sup <= inf){
//					tr(sup, m, inf, m, enc(sup, m, m), enc(inf, m, m));
//				}
//			}
//		}
//		{
//			int inf = Math.min(co[0], co[1]);
//			if(co[0] == co[1])inf--;
//			int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);
//
////			if(sup == 0)sup++;
//			if(sup <= inf){
//				tr(sup, sup, inf, inf, enc(sup, sup, m), enc(inf, inf, m));
//			}
//		}
//		{
//			int inf = co[0];
//			if(co[1] == 0)inf--;
//			int sup = Math.max(0, co[0] - n + co[1]);
//			if(sup <= inf){
//				tr(sup, 0, inf, 0, enc(sup, 0, m), enc(inf, 0, m));
//			}
//		}

		if(n <= Math.sqrt(Math.sqrt(m))){
			solveH(m, n);
		}else{
			solveB(m, n);
		}
	}

	void solveB(int m, int n){
			// (a, 0), (a, a), (a, m)
			BitSet visitedo = new BitSet();
			BitSet visitedh = new BitSet();
			BitSet q = new BitSet();
			q.set(0);
			boolean iso = true;
			int step = 0;

			while(!q.isEmpty()){
				if(!iso && q.get(2 * m))break;
//				tr(step, q);
				BitSet nq = new BitSet();
				if(iso){
					visitedh.or(q);
				}else{
					visitedo.or(q);
				}
				for(int cur = q.nextSetBit(0);cur != -1;cur = q.nextSetBit(cur+1)){
					int[] co = dec(cur, m);
					if(iso){
						{
							if(co[1] == 0){
								int inf = co[0] + 1;
								int sup = Math.min(m, co[0] + n);
								if(inf <= sup){
									nq.set(enc(inf, 0, m), enc(sup, 0, m) + 1);
								}
							}
						}
						{
							int inf = Math.max(co[0], co[1]);
							if(co[0] == co[1])inf++;
							int sup = Math.min(m, (n + co[0] + co[1]) / 2);

							if(inf <= sup){
								nq.set(enc(inf, inf, m), enc(sup, sup, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == m)inf++;
							int sup = Math.min(m - 1, co[0] + n - m + co[1]);
							if(inf <= sup){
								nq.set(enc(inf, m, m), enc(sup, m, m) + 1);
							}
						}
					}else{
						{
							if(co[1] == m){
								int inf = co[0] - 1;
								int sup = Math.max(0, co[0] - n);
								if(sup <= inf){
									nq.set(enc(sup, m, m), enc(inf, m, m) + 1);
								}
							}
						}
						{
							int inf = Math.min(co[0], co[1]);
							if(co[0] == co[1])inf--;
							int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//							if(sup == 0)sup++;
							if(sup <= inf){
								nq.set(enc(sup, sup, m), enc(inf, inf, m) + 1);
							}
						}
						{
							int inf = co[0];
							if(co[1] == 0)inf--;
							int sup = Math.max(0, co[0] - n + co[1]);
							if(sup <= inf){
								nq.set(enc(sup, 0, m), enc(inf, 0, m) + 1);
							}
						}
					}
				}
				if(iso){
					nq.andNot(visitedo);
				}else{
					nq.andNot(visitedh);
				}
				q = nq;
				step++;
				iso = !iso;
			}
			if(q.isEmpty()){
				out.println(-1);
			}else{
				out.println(step);
			}
	}

	void solveH(int m, int n){

		// (a, 0), (a, a), (a, m)
		HashSet<Integer> visitedo = new HashSet<Integer>();
		HashSet<Integer> visitedh = new HashSet<Integer>();
		HashSet<Integer> q = new HashSet<Integer>();
		q.add(0);
		boolean iso = true;
		int step = 0;

		while(!q.isEmpty()){
			if(!iso && q.contains(2 * m))break;
//			tr(step, q);
			HashSet<Integer> nq = new HashSet<Integer>();
			if(iso){
				visitedh.addAll(q);
			}else{
				visitedo.addAll(q);
			}
			for(int cur : q){
				int[] co = dec(cur, m);
				if(iso){
					{
						if(co[1] == 0){
							int inf = co[0] + 1;
							int sup = Math.min(m, co[0] + n);
							if(inf <= sup){
								for(int i = enc(inf, 0, m);i <= enc(sup, 0, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.max(co[0], co[1]);
						if(co[0] == co[1])inf++;
						int sup = Math.min(m, (n + co[0] + co[1]) / 2);

						if(inf == 0)inf = 1;
						if(inf <= sup){
							for(int i = enc(inf, inf, m);i <= enc(sup, sup, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == m)inf++;
						int sup = Math.min(m - 1, co[0] + n - m + co[1]);
						if(inf <= sup){
							for(int i = enc(inf, m, m);i <= enc(sup, m, m);i++){
								nq.add(i);
							}
						}
					}
				}else{
					{
						if(co[1] == m){
							int inf = co[0] - 1;
							int sup = Math.max(0, co[0] - n);
							if(sup <= inf){
								for(int i = enc(sup, m, m);i <= enc(inf, m, m);i++){
									nq.add(i);
								}
							}
						}
					}
					{
						int inf = Math.min(co[0], co[1]);
						if(co[0] == co[1])inf--;
						int sup = Math.max(1, (-n + co[0] + co[1] + 1) / 2);

//						if(sup == 0)sup++;
						if(sup <= inf){
							for(int i = enc(sup, sup, m);i <= enc(inf, inf, m);i++){
								nq.add(i);
							}
						}
					}
					{
						int inf = co[0];
						if(co[1] == 0)inf--;
						int sup = Math.max(0, co[0] - n + co[1]);
						if(sup <= inf){
							for(int i = enc(sup, 0, m);i <= enc(inf, 0, m);i++){
								nq.add(i);
							}
						}
					}
				}
			}
			if(iso){
				nq.removeAll(visitedo);
			}else{
				nq.removeAll(visitedh);
			}
			q = nq;
			step++;
			iso = !iso;
		}
		if(q.isEmpty()){
			out.println(-1);
		}else{
			out.println(step);
		}
	}

	void run() throws Exception
	{
		in = INPUT.isEmpty() ? new Scanner(System.in) : new Scanner(INPUT);
		out = new PrintWriter(System.out);

		out.println(INPUT);
		solve();
		out.flush();
	}

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

	int ni() { return Integer.parseInt(in.next()); }
	void tr(Object... o) { if(INPUT.length() != 0)System.out.println(o.length > 1 || o[0].getClass().isArray() ? Arrays.deepToString(o) : o[0]); }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.stream.IntStream;
import java.util.PriorityQueue;
import java.util.AbstractQueue;
import java.util.Random;
import java.util.ArrayList;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.util.Collection;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.util.List;
import java.util.stream.Stream;
import java.io.Closeable;
import java.io.Writer;
import java.util.Comparator;
import java.io.InputStream;

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

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

    static class DFindingLines {
        int interval = 19000;
        int inf = (int) 1e8;
        Comparator<Interval> comp = (a, b) -> a.len == b.len ? Integer.compare(a.l, b.l) : -Integer.compare(a.len, b.len);
        PriorityQueue<Interval> ySet = new PriorityQueue<>((int) 1e4, comp);
        List<Integer> xLines = new ArrayList<>();
        FastInput in;
        FastOutput out;
        RandomWrapper rw = new RandomWrapper(new Random());
        int limit = (int) 3e5;

        public void solve(int testNumber, FastInput in, FastOutput out) {
            this.in = in;
            this.out = out;
            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), false, 0);
            }
            xLines.sort(Comparator.naturalOrder());
            int[] xArrays = xLines.stream()
                    .mapToInt(Integer::intValue).toArray();

            clear();
            ySet.clear();
            int left = -inf;
            for (int x : xArrays) {
                Interval interval = new Interval(left, x - 1);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
                left = x + 1;
            }
            {
                Interval interval = new Interval(left, inf);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
            }

            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), true, 0);
            }
            xLines.sort(Comparator.naturalOrder());
            int[] yArrays = xLines.stream()
                    .mapToInt(Integer::intValue).toArray();

            out.printf("1 %d %d", xArrays.length, yArrays.length).println();
            for (int x : xArrays) {
                out.append(x).append(' ');
            }
            out.println();
            for (int y : yArrays) {
                out.append(y).append(' ');
            }
            out.println().flush();
        }

        public void clear() {
            ySet.clear();
            xLines.clear();
            ySet.add(new Interval(-inf, inf));
        }

        public void check(Interval x, boolean inv, int depth) {
            if (x.isEmpty()) {
                return;
            }

            Interval y = ySet.peek();
            int cx = x.middle();
            int cy = y.middle();
            int dist = ask(cx, cy, inv);

            if (!(cx - dist >= x.l || cx + dist <= x.r)) {
                return;
            }

            if (cx - dist >= x.l && exist(cx - dist, inv, 3)) {
                xLines.add(cx - dist);
                for (Interval interval : x.split(cx - dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (dist != 0 && cx + dist <= x.r && exist(cx + dist, inv, 3)) {
                xLines.add(cx + dist);
                for (Interval interval : x.split(cx + dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cy - dist >= y.l && exist(cy - dist, !inv, 3)) {
                ySet.remove();
                for (Interval interval : y.split(cy - dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
                check(x, inv, depth + 1);
                return;
            }

            if (dist != 0 && cy + dist <= y.r && exist(cy + dist, !inv, 3)) {
                ySet.remove();
                for (Interval interval : y.split(cy + dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
                check(x, inv, depth + 1);
                return;
            }

        }

        public boolean exist(int x, boolean inv, int time) {
            for (int i = 0; i < time; i++) {
                int y1 = rw.nextInt(-inf, inf);
                if (ask(x, y1, inv) != 0) {
                    return false;
                }
            }
            return true;
        }

        public int ask(int x, int y, boolean inv) {
            if (inv) {
                int tmp = x;
                x = y;
                y = tmp;
            }

            if (limit-- == 0) {
                throw new RuntimeException();
            }

            out.append("0 ").append(x).append(' ').append(y).println().flush();
            return in.readInt();
        }

    }

    static class Interval {
        int l;
        int r;
        int len;

        public int middle() {
            return (r + l) / 2;
        }

        public Interval(int l, int r) {
            this.l = l;
            this.r = r;
            this.len = r - l + 1;
        }

        public boolean isEmpty() {
            return r < l;
        }

        public Interval[] split(int x) {
            return new Interval[]{new Interval(l, x - 1), new Interval(x + 1, r)};
        }

        public String toString() {
            return String.format("[%d, %d]", l, r);
        }

    }

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

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

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

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

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            return this;
        }

        public FastOutput printf(String format, Object... args) {
            cache.append(String.format(format, args));
            return this;
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

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

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

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

    }

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

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

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

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

        public int readInt() {
            int sign = 1;

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

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

            return val;
        }

    }

    static class RandomWrapper {
        private Random random;

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.AbstractQueue;
import java.util.Random;
import java.util.TreeSet;
import java.io.OutputStreamWriter;
import java.io.OutputStream;
import java.io.IOException;
import java.io.UncheckedIOException;
import java.io.Closeable;
import java.io.Writer;
import java.util.Comparator;
import java.io.InputStream;

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

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

    static class DFindingLines {
        int interval = 19000;
        int inf = (int) 1e8;
        Comparator<Interval> comp = (a, b) -> a.len == b.len ? Integer.compare(a.l, b.l) : -Integer.compare(a.len, b.len);
        PriorityQueue<Interval> ySet = new PriorityQueue<>((int) 1e4, comp);
        IntegerList yLines = new IntegerList();
        TreeSet<Interval> xSet = new TreeSet<>(comp);
        IntegerList xLines = new IntegerList();
        FastInput in;
        FastOutput out;
        RandomWrapper rw = new RandomWrapper(new Random());

        public void solve(int testNumber, FastInput in, FastOutput out) {
            this.in = in;
            this.out = out;
            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), false, 0);
            }
            xLines.unique();
            int[] xArrays = xLines.toArray();

            clear();
            ySet.clear();
            int left = -inf;
            for (int x : xArrays) {
                Interval interval = new Interval(left, x - 1);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
                left = x + 1;
            }
            {
                Interval interval = new Interval(left, inf);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
            }

            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), true, 0);
            }
            xLines.unique();
            int[] yArrays = xLines.toArray();

            out.printf("1 %d %d", xArrays.length, yArrays.length).println();
            for (int x : xArrays) {
                out.append(x).append(' ');
            }
            out.println();
            for (int y : yArrays) {
                out.append(y).append(' ');
            }
            out.println().flush();
        }

        public void clear() {
            ySet.clear();
            xSet.clear();
            yLines.clear();
            xLines.clear();
            ySet.add(new Interval(-inf, inf));
            xSet.add(new Interval(-inf, inf));
        }

        public void check(Interval x, boolean inv, int depth) {
            if (x.isEmpty()) {
                return;
            }

            Interval y = ySet.peek();
            int cx = x.middle();
            int cy = y.middle();
            int dist = ask(cx, cy, inv);

            if (!(cx - dist >= x.l || cx + dist <= x.r)) {
                return;
            }

            if (cx - dist >= x.l && exist(cx - dist, inv)) {
                xLines.add(cx - dist);
                for (Interval interval : x.split(cx - dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cx + dist <= x.r && exist(cx + dist, inv)) {
                xLines.add(cx + dist);
                for (Interval interval : x.split(cx + dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cy - dist >= y.l && exist(cy - dist, !inv)) {
                ySet.remove();
                for (Interval interval : y.split(cy - dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            if (cy + dist <= y.r && exist(cy + dist, !inv)) {
                ySet.remove();
                for (Interval interval : y.split(cy + dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            //check(x, inv, depth + 1);
        }

        public boolean exist(int x, boolean inv) {
            int y1 = rw.nextInt(-inf, inf);
            int y2 = rw.nextInt(-inf, inf);
            int y3 = rw.nextInt(-inf, inf);
            int y4 = rw.nextInt(-inf, inf);
            return ask(x, y1, inv) == 0 && ask(x, y2, inv) == 0 && ask(x, y3, inv) == 0 &&
                    ask(x, y4, inv) == 0;
        }

        public int ask(int x, int y, boolean inv) {
            if (inv) {
                int tmp = x;
                x = y;
                y = tmp;
            }

            out.append("0 ").append(x).append(' ').append(y).println().flush();
            return in.readInt();
        }

    }

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

    }

    static class Interval {
        int l;
        int r;
        int len;

        public int middle() {
            return (r + l) / 2;
        }

        public Interval(int l, int r) {
            this.l = l;
            this.r = r;
            this.len = r - l + 1;
        }

        public boolean isEmpty() {
            return r < l;
        }

        public Interval[] split(int x) {
            return new Interval[]{new Interval(l, x - 1), new Interval(x + 1, r)};
        }

        public String toString() {
            return String.format("[%d, %d]", l, r);
        }

    }

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

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

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

        public IntegerList() {
            this(0);
        }

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

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

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

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

        public void sort() {
            if (size <= 1) {
                return;
            }
            Randomized.shuffle(data, 0, size);
            Arrays.sort(data, 0, size);
        }

        public void unique() {
            if (size <= 1) {
                return;
            }

            sort();
            int wpos = 1;
            for (int i = 1; i < size; i++) {
                if (data[i] != data[wpos - 1]) {
                    data[wpos++] = data[i];
                }
            }
            size = wpos;
        }

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

        public void clear() {
            size = 0;
        }

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

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

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

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

    }

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

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

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

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

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            return this;
        }

        public FastOutput printf(String format, Object... args) {
            cache.append(String.format(format, args));
            return this;
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

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

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

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

    }

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

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

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

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

        public int readInt() {
            int sign = 1;

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

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

            return val;
        }

    }

    static class Randomized {
        public static void shuffle(int[] data, int from, int to) {
            to--;
            for (int i = from; i <= to; i++) {
                int s = nextInt(i, to);
                int tmp = data[i];
                data[i] = data[s];
                data[s] = tmp;
            }
        }

        public static int nextInt(int l, int r) {
            return RandomWrapper.INSTANCE.nextInt(l, r);
        }

    }

    static class RandomWrapper {
        private Random random;
        public static RandomWrapper INSTANCE = new RandomWrapper(new Random());

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.io.IOException;
import java.util.Random;
import java.util.TreeSet;
import java.io.UncheckedIOException;
import java.io.Closeable;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Comparator;
import java.io.InputStream;

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

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

    static class DFindingLines {
        int interval = 18000;
        int inf = (int) 1e8;
        Comparator<Interval> comp = (a, b) -> a.len == b.len ? Integer.compare(a.l, b.l) : Integer.compare(a.len, b.len);
        TreeSet<Interval> ySet = new TreeSet<>(comp);
        IntegerList yLines = new IntegerList();
        TreeSet<Interval> xSet = new TreeSet<>(comp);
        IntegerList xLines = new IntegerList();
        FastInput in;
        FastOutput out;
        RandomWrapper rw = new RandomWrapper(new Random(0));

        public void solve(int testNumber, FastInput in, FastOutput out) {
            this.in = in;
            this.out = out;
            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), false, 0);
            }
            xLines.unique();
            int[] xArrays = xLines.toArray();

            clear();
            ySet.clear();
            int left = -inf;
            for (int x : xArrays) {
                Interval interval = new Interval(left, x - 1);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
                left = x + 1;
            }
            {
                Interval interval = new Interval(left, inf);
                if (!interval.isEmpty()) {
                    ySet.add(interval);
                }
            }

            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), true, 0);
            }
            xLines.unique();
            int[] yArrays = xLines.toArray();

            out.printf("1 %d %d", xArrays.length, yArrays.length).println();
            for (int x : xArrays) {
                out.append(x).append(' ');
            }
            out.println();
            for (int y : yArrays) {
                out.append(y).append(' ');
            }
            out.println().flush();
        }

        public void clear() {
            ySet.clear();
            xSet.clear();
            yLines.clear();
            xLines.clear();
            ySet.add(new Interval(-inf, inf));
            xSet.add(new Interval(-inf, inf));
        }

        public void check(Interval x, boolean inv, int depth) {
            if (x.isEmpty()) {
                return;
            }

            Interval y = ySet.last();
            int cx = x.middle();
            int cy = y.middle();
            int dist = ask(cx, cy, inv);

            if (!(cx - dist >= x.l || cx + dist <= x.r)) {
                return;
            }

            if (cx - dist >= x.l && exist(cx - dist, inv)) {
                xLines.add(cx - dist);
                for (Interval interval : x.split(cx - dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cx + dist <= x.r && exist(cx + dist, inv)) {
                xLines.add(cx + dist);
                for (Interval interval : x.split(cx + dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cy - dist >= y.l && exist(cy - dist, !inv)) {
                ySet.remove(y);
                for (Interval interval : y.split(cy - dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            if (cy + dist <= y.r && exist(cy + dist, !inv)) {
                ySet.remove(y);
                for (Interval interval : y.split(cy + dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            //check(x, inv, depth + 1);
        }

        public boolean exist(int x, boolean inv) {
            int y1 = rw.nextInt(-inf, inf);
            int y2 = rw.nextInt(-inf, inf);
            int y3 = rw.nextInt(-inf, inf);
            return ask(x, y1, inv) == 0 && ask(x, y2, inv) == 0 && ask(x, y3, inv) == 0;
        }

        public int ask(int x, int y, boolean inv) {
            if (inv) {
                int tmp = x;
                x = y;
                y = tmp;
            }

            out.append("0 ").append(x).append(' ').append(y).println().flush();
            return in.readInt();
        }

    }

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

    }

    static class Interval {
        int l;
        int r;
        int len;

        public int middle() {
            return (r + l) / 2;
        }

        public Interval(int l, int r) {
            this.l = l;
            this.r = r;
            this.len = r - l + 1;
        }

        public boolean isEmpty() {
            return r < l;
        }

        public Interval[] split(int x) {
            return new Interval[]{new Interval(l, x - 1), new Interval(x + 1, r)};
        }

        public String toString() {
            return String.format("[%d, %d]", l, r);
        }

    }

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

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

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

        public IntegerList() {
            this(0);
        }

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

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

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

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

        public void sort() {
            if (size <= 1) {
                return;
            }
            Randomized.shuffle(data, 0, size);
            Arrays.sort(data, 0, size);
        }

        public void unique() {
            if (size <= 1) {
                return;
            }

            sort();
            int wpos = 1;
            for (int i = 1; i < size; i++) {
                if (data[i] != data[wpos - 1]) {
                    data[wpos++] = data[i];
                }
            }
            size = wpos;
        }

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

        public void clear() {
            size = 0;
        }

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

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

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

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

    }

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

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

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

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

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            return this;
        }

        public FastOutput printf(String format, Object... args) {
            cache.append(String.format(format, args));
            return this;
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

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

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

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

    }

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

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

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

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

        public int readInt() {
            int sign = 1;

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

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

            return val;
        }

    }

    static class Randomized {
        public static void shuffle(int[] data, int from, int to) {
            to--;
            for (int i = from; i <= to; i++) {
                int s = nextInt(i, to);
                int tmp = data[i];
                data[i] = data[s];
                data[s] = tmp;
            }
        }

        public static int nextInt(int l, int r) {
            return RandomWrapper.INSTANCE.nextInt(l, r);
        }

    }

    static class RandomWrapper {
        private Random random;
        public static RandomWrapper INSTANCE = new RandomWrapper(new Random());

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Arrays;
import java.io.IOException;
import java.util.Random;
import java.util.TreeSet;
import java.io.UncheckedIOException;
import java.io.Closeable;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.Comparator;
import java.io.InputStream;

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

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

    static class DFindingLines {
        int interval = 18000;
        int inf = (int) 1e8;
        Comparator<Interval> comp = (a, b) -> a.len == b.len ? Integer.compare(a.l, b.l) : Integer.compare(a.len, b.len);
        TreeSet<Interval> ySet = new TreeSet<>(comp);
        IntegerList yLines = new IntegerList();
        TreeSet<Interval> xSet = new TreeSet<>(comp);
        IntegerList xLines = new IntegerList();
        FastInput in;
        FastOutput out;
        RandomWrapper rw = new RandomWrapper(new Random(0));

        public void solve(int testNumber, FastInput in, FastOutput out) {
            this.in = in;
            this.out = out;
            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), false, 0);
            }
            xLines.unique();
            int[] xArrays = xLines.toArray();

            clear();
            for (int i = -inf; i <= inf; i += interval) {
                int l = i;
                int r = Math.min(inf, i + interval - 1);
                check(new Interval(l, r), true, 0);
            }
            xLines.unique();
            int[] yArrays = xLines.toArray();

            out.printf("1 %d %d", xArrays.length, yArrays.length).println();
            for (int x : xArrays) {
                out.append(x).append(' ');
            }
            out.println();
            for (int y : yArrays) {
                out.append(y).append(' ');
            }
            out.println().flush();
        }

        public void clear() {
            ySet.clear();
            xSet.clear();
            yLines.clear();
            xLines.clear();
            ySet.add(new Interval(-inf, inf));
            xSet.add(new Interval(-inf, inf));
        }

        public void check(Interval x, boolean inv, int depth) {
            if (x.isEmpty()) {
                return;
            }

            Interval y = ySet.last();
            int cx = x.middle();
            int cy = y.middle();
            int dist = ask(cx, cy, inv);

            if (!(cx - dist >= x.l || cx + dist <= x.r)) {
                return;
            }

            if (cx - dist >= x.l && exist(cx - dist, inv)) {
                xLines.add(cx - dist);
                for (Interval interval : x.split(cx - dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cx + dist <= x.r && exist(cx + dist, inv)) {
                xLines.add(cx + dist);
                for (Interval interval : x.split(cx + dist)) {
                    check(interval, inv, depth + 1);
                }
                return;
            }

            if (cy - dist >= y.l && exist(cy - dist, !inv)) {
                ySet.remove(y);
                for (Interval interval : y.split(cy - dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            if (cy + dist <= y.r && exist(cy + dist, !inv)) {
                ySet.remove(y);
                for (Interval interval : y.split(cy + dist)) {
                    if (!interval.isEmpty()) {
                        ySet.add(interval);
                    }
                }
            }

            //check(x, inv, depth + 1);
        }

        public boolean exist(int x, boolean inv) {
            int y1 = rw.nextInt(-inf, inf);
            int y2 = rw.nextInt(-inf, inf);
            return ask(x, y1, inv) == 0 && ask(x, y2, inv) == 0;
        }

        public int ask(int x, int y, boolean inv) {
            if (inv) {
                int tmp = x;
                x = y;
                y = tmp;
            }

            out.append("0 ").append(x).append(' ').append(y).println().flush();
            return in.readInt();
        }

    }

    static class Interval {
        int l;
        int r;
        int len;

        public int middle() {
            return (r + l) / 2;
        }

        public Interval(int l, int r) {
            this.l = l;
            this.r = r;
            this.len = r - l + 1;
        }

        public boolean isEmpty() {
            return r < l;
        }

        public Interval[] split(int x) {
            return new Interval[]{new Interval(l, x - 1), new Interval(x + 1, r)};
        }

        public String toString() {
            return String.format("[%d, %d]", l, r);
        }

    }

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

    }

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

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

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

        public IntegerList() {
            this(0);
        }

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

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

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

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

        public void sort() {
            if (size <= 1) {
                return;
            }
            Randomized.shuffle(data, 0, size);
            Arrays.sort(data, 0, size);
        }

        public void unique() {
            if (size <= 1) {
                return;
            }

            sort();
            int wpos = 1;
            for (int i = 1; i < size; i++) {
                if (data[i] != data[wpos - 1]) {
                    data[wpos++] = data[i];
                }
            }
            size = wpos;
        }

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

        public void clear() {
            size = 0;
        }

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

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

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

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

    }

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

        public FastOutput append(CharSequence csq) {
            cache.append(csq);
            return this;
        }

        public FastOutput append(CharSequence csq, int start, int end) {
            cache.append(csq, start, end);
            return this;
        }

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

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

        public FastOutput append(char c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(int c) {
            cache.append(c);
            return this;
        }

        public FastOutput append(String c) {
            cache.append(c);
            return this;
        }

        public FastOutput printf(String format, Object... args) {
            cache.append(String.format(format, args));
            return this;
        }

        public FastOutput println() {
            cache.append(System.lineSeparator());
            return this;
        }

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

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

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

    }

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

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

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

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

        public int readInt() {
            int sign = 1;

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

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

            return val;
        }

    }

    static class Randomized {
        public static void shuffle(int[] data, int from, int to) {
            to--;
            for (int i = from; i <= to; i++) {
                int s = nextInt(i, to);
                int tmp = data[i];
                data[i] = data[s];
                data[s] = tmp;
            }
        }

        public static int nextInt(int l, int r) {
            return RandomWrapper.INSTANCE.nextInt(l, r);
        }

    }

    static class RandomWrapper {
        private Random random;
        public static RandomWrapper INSTANCE = new RandomWrapper(new Random());

        public RandomWrapper() {
            this(new Random());
        }

        public RandomWrapper(Random random) {
            this.random = random;
        }

        public int nextInt(int l, int r) {
            return random.nextInt(r - l + 1) + l;
        }

    }
}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.BufferedReader;
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);
        HZSShufflesCards solver = new HZSShufflesCards();
        solver.solve(1, in, out);
        out.close();
    }

    static class HZSShufflesCards {
        NumberTheory.Mod998 mod = new NumberTheory.Mod998();
        int n;
        int m;

        public void solve(int testNumber, InputReader in, PrintWriter out) {
            n = in.nextInt();
            m = in.nextInt();

            mod.fInv(n + m);

            long phaseSize = 1;
            long p = 1;
            for (int i = 0; p != 0; i++) {
                p = mod.mult(p, n - i, mod.smallInv(n + m - i));
                phaseSize = mod.add(phaseSize, p);
            }

            long answer = 0;
            for (int k = 1; k <= n; k++) {
                long sign = mod.paritySign(k + 1);
                long numPhases = mod.mult(m + k, mod.smallInv(k));
                long term = mod.mult(sign, mod.ncr(n, k), numPhases, phaseSize);
                answer = mod.add(answer, term);
            }

            out.println(answer);
        }

    }

    static class InputReader {
        public final BufferedReader reader;
        public StringTokenizer tokenizer;

        public InputReader(InputStream stream) {
            reader = new BufferedReader(new InputStreamReader(stream), 32768);
            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());
        }

    }

    static class Util {
        public static void ASSERT(boolean assertion) {
            if (!assertion)
                throw new AssertionError();
        }

        private Util() {
        }

    }

    static class IntStack {
        int[] array;
        int size = 0;

        public IntStack() {
            this(8);
        }

        public IntStack(int capacity) {
            array = new int[capacity];
        }

        public void push(int item) {
            if (size >= array.length)
                array = resize(array);
            array[size++] = item;
        }

        public int size() {
            return size;
        }

        public int get(int i) {
            Util.ASSERT(i < size);
            return array[i];
        }

        private static int[] resize(int[] array) {
            int[] newArray = new int[array.length << 1];
            System.arraycopy(array, 0, newArray, 0, array.length);
            return newArray;
        }

        public String toString() {
            int[] trimmed = new int[size];
            System.arraycopy(array, 0, trimmed, 0, size);
            return Arrays.toString(trimmed);
        }

    }

    static class NumberTheory {
        private static void ASSERT(boolean assertion) {
            if (!assertion)
                throw new AssertionError();
        }

        public abstract static class Modulus<M extends NumberTheory.Modulus<M>> {
            final IntStack factorial = new IntStack();
            final IntStack invFactorial = new IntStack();

            public abstract long modulus();

            public Modulus() {
                super();
                factorial.push(1);
                invFactorial.push(1);
            }

            public long fact(int n) {
                while (factorial.size() <= n) {
                    factorial.push((int) mult(factorial.get(factorial.size() - 1), factorial.size()));
                }

                return factorial.get(n);
            }

            public long fInv(int n) {
                int lastKnown = invFactorial.size() - 1;

                if (lastKnown < n) {
                    long[] fInv = new long[n - lastKnown];
                    fInv[0] = inv(fact(n));
                    for (int i = 1; i < fInv.length; i++) {
                        fInv[i] = mult(fInv[i - 1], n - i + 1);
                    }
                    for (int i = fInv.length - 1; i >= 0; i--) {
                        invFactorial.push((int) fInv[i]);
                    }
                }

                return invFactorial.get(n);
            }

            public long paritySign(long k) {
                return (k & 1) == 0 ? 1 : modulus() - 1;
            }

            public long ncr(int n, int r) {
                ASSERT(n >= 0);
                if (r < 0 || n < r)
                    return 0;
                return mult(fact(n), mult(fInv(r), fInv(n - r)));
            }

            public long smallInv(int n) {
                return mult(fInv(n), fact(n - 1));
            }

            public long normalize(long x) {
                x %= modulus();
                if (x < 0)
                    x += modulus();
                return x;
            }

            public long add(long a, long b) {
                long v = a + b;
                return v < modulus() ? v : v - modulus();
            }

            public long mult(long... x) {
                long r = 1;
                for (long i : x)
                    r = mult(r, i);
                return r;
            }

            public long mult(long a, long b) {
                return (a * b) % modulus();
            }

            public long inv(long value) {
                long g = modulus(), x = 0, y = 1;
                for (long r = value; r != 0; ) {
                    long q = g / r;
                    g %= r;

                    long temp = g;
                    g = r;
                    r = temp;

                    x -= q * y;

                    temp = x;
                    x = y;
                    y = temp;
                }

                ASSERT(g == 1);
                ASSERT(y == modulus() || y == -modulus());

                return normalize(x);
            }

        }

        public static class Mod998 extends NumberTheory.Modulus<NumberTheory.Mod998> {
            public long modulus() {
                return 998_244_353L;
            }

        }

    }
}