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

public class Tanks implements Runnable {
    class Point {
        int x;
        int y;

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

    }

    Point readPoint() throws IOException {
        int x = nextInt();
        int y = nextInt();
        return new Point(x, y);
    }

    private void solve() throws IOException {
        Point A = readPoint();
        Point B = readPoint();
        int n = nextInt();
        Point[] tank = new Point[n];
        double[] alpha = new double[n];
        double[] w = new double[n];
        for (int i = 0; i < n; ++i) {
            tank[i] = readPoint();
            alpha[i] = nextDouble();
            if (alpha[i] > Math.PI) alpha[i] -= 2 * Math.PI;
            w[i] = nextDouble();
        }
        int canSuffer = nextInt();
        double[] maxHit = new double[n + 1];
        for (int i = 0; i < n; ++i) {
            maxHit[i] = processTank(A, B, tank[i], alpha[i], w[i]);
        }
        Arrays.sort(maxHit);
        writer.println(maxHit[n - canSuffer]);
    }

    private double processTank(Point A, Point B, Point tank, double alpha, double w) {
        if (w == 0)
            return 0;
        return Math.max(process(A, B, tank, alpha, w), process(A, B, tank, alpha, -w));
    }

    private double process(Point a, Point b, Point tank, double alpha, double w) {
        double alphaA = Math.atan2(a.y - tank.y, a.x - tank.x);
        double alphaB = Math.atan2(b.y - tank.y, b.x - tank.x);
        if (Math.signum(alphaA - alpha) != Math.signum(w)) alphaA += Math.PI * 2 * Math.signum(w);
        if (Math.signum(alphaB - alpha) != Math.signum(w)) alphaB += Math.PI * 2 * Math.signum(w);
        double tA = (alphaA - alpha) / w;
        double tB = (alphaB - alpha) / w;
        double dy = b.y - a.y;
        double dx = b.x - a.x;
        double dist = Math.sqrt(dx * dx + dy * dy);
        if (tB <= tA) {
            return dist / tB;
        } else {
            double best = 0;
            double bestVal = 0;
            double res = dist / tB;
            for (int i = 0; i <= 100; ++i) {
                double middle = i / 100.0;
                double x = a.x + middle * dx;
                double y = a.y + middle * dy;
                double alphaM2 = Math.atan2(y - tank.y, x - tank.x);
                if (Math.signum(alphaM2 - alpha) != Math.signum(w)) alphaM2 += Math.PI * 2 * Math.signum(w);
                double tM = (alphaM2 - alpha) / w;
                double cur = middle * dist / tM;
                res = Math.max(res, cur);
                if (cur > bestVal) {
                    bestVal = cur;
                    best = middle;
                }
            }
            double left = Math.max(0, best - 0.03);
            double right = Math.min(1, best + 0.03);
            for (int i = 0; i < 300; ++i) {
                double middle2;
                double tM2;
                {
                    middle2 = (left + 2 * right) / 3;
                    double x = a.x + middle2 * dx;
                    double y = a.y + middle2 * dy;
                    double alphaM2 = Math.atan2(y - tank.y, x - tank.x);
                    if (Math.signum(alphaM2 - alpha) != Math.signum(w)) alphaM2 += Math.PI * 2 * Math.signum(w);
                    tM2 = (alphaM2 - alpha) / w;
                }
                double middle1;
                double tM1;
                {
                    middle1 = (2 * left + right) / 3;
                    double x = a.x + middle1 * dx;
                    double y = a.y + middle1 * dy;
                    double alphaM1 = Math.atan2(y - tank.y, x - tank.x);
                    if (Math.signum(alphaM1 - alpha) != Math.signum(w)) alphaM1 += Math.PI * 2 * Math.signum(w);
                    tM1 = (alphaM1 - alpha) / w;
                }
                double valM1 = dist * middle1 / tM1;
                double valM2 = dist * middle2 / tM2;
                res = Math.max(res, valM1);
                res = Math.max(res, valM2);
                if (valM1 > valM2) {
                    right = middle2;
                } else {
                    left = middle1;
                }
            }
            return res;
        }
    }

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

    BufferedReader reader;
    StringTokenizer tokenizer;
    PrintWriter writer;

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

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

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

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

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


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Set;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.util.Collections;
import java.io.InputStream;

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

    static class TaskC {
        final double eps = 1e-10;

        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            int n = in.nextInt();
            Circle[] circles = new Circle[n];
            for (int i = 0; i < n; i++) {
                int x = in.nextInt();
                int y = in.nextInt();
                int r = in.nextInt();
                circles[i] = new Circle();
                circles[i].o = new Point(x, y);
                circles[i].r = r;
            }

            Set<Point> all = new TreeSet<>();
            for (int i = 0; i < n; i++) {
                for (int j = i + 1; j < n; j++) {
                    List<Point> inter = intersect(circles[i], circles[j]);
                    if (inter == null) {
                        continue;
                    }
                    all.addAll(inter);
                }
            }

            Map<Point, Integer> pointId = new TreeMap<>();
            List<Set<Integer>> adj = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                List<Double> angles = new ArrayList<>();
                final int K = 10;
                for (int j = 0; j < K; j++) {
                    angles.add(Math.PI * 2 * j / K + 1e-8);
                }
                for (Point p : all) {
                    if (circles[i].contains(p)) {
                        double dx = p.x - circles[i].o.x;
                        double dy = p.y - circles[i].o.y;
                        angles.add(Math.atan2(dy, dx));
                    }
                }
                Collections.sort(angles);
                Point dir = new Point(1, 0).scale(circles[i].r);
                for (int j = 0; j < angles.size(); j++) {
                    Point p = circles[i].o.add(dir.rotate(angles.get(j)));
                    getId(p, pointId, adj);
                }
                for (int j = 0; j < angles.size(); j++) {
                    Point p = circles[i].o.add(dir.rotate(angles.get(j)));
                    Point q = circles[i].o.add(dir.rotate(angles.get((j + 1) % angles.size())));
                    int u = pointId.get(p);
                    int v = pointId.get(q);
                    adj.get(u).add(v);
                    adj.get(v).add(u);
                }
            }

            int v = adj.size();
            int e = 0;
            for (int i = 0; i < v; i++) {
                e += adj.get(i).size();
            }
            e /= 2;

            int comps = 0;
            boolean[] was = new boolean[v];
            for (int i = 0; i < v; i++) {
                if (!was[i]) {
                    ++comps;
                    dfs(i, was, adj);
                }
            }

            out.println(1 + comps + e - v);
        }

        private void dfs(int i, boolean[] was, List<Set<Integer>> adj) {
            was[i] = true;
            for (int j : adj.get(i)) {
                if (!was[j]) {
                    dfs(j, was, adj);
                }
            }
        }

        private void getId(Point p, Map<Point, Integer> pointId, List<Set<Integer>> adj) {
            if (!pointId.containsKey(p)) {
                int sz = pointId.size();
                pointId.put(p, sz);
                adj.add(new TreeSet<>());
            }
        }

        private List<Point> intersect(Circle c1, Circle c2) {
            double dx = c1.o.x - c2.o.x;
            double dy = c1.o.y - c2.o.y;
            double sr = c1.r + c2.r;
            if (dx * dx + dy * dy > sr * sr + eps) {
                return null;
            }
            double d = Math.sqrt(dx * dx + dy * dy);
            if (d + Math.min(c1.r, c2.r) < Math.max(c1.r, c2.r) - eps) {
                return null;
            }
            double cos = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d);
            if (cos < -1) {
                cos = -1;
            }
            if (cos > 1) {
                cos = 1;
            }
            List<Point> res = new ArrayList<>();
            double alpha = Math.acos(cos);
            Point dir = c2.o.sub(c1.o).norm();
            res.add(c1.o.add(dir.scale(c1.r).rotate(+alpha)));
            res.add(c1.o.add(dir.scale(c1.r).rotate(-alpha)));
            return res;
        }

        class Point implements Comparable<Point> {
            double x;
            double y;

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

            Point add(Point o) {
                return new Point(x + o.x, y + o.y);
            }

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

            Point rotate(double alpha) {
                double c = Math.cos(alpha);
                double s = Math.sin(alpha);
                double nx = x * c - y * s;
                double ny = x * s + y * c;
                return new Point(nx, ny);
            }

            Point norm() {
                double len = length();
                return scale(1.0 / len);
            }

            Point scale(double f) {
                return new Point(f * x, f * y);
            }

            double length() {
                return Math.sqrt(x * x + y * y);
            }

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

            public boolean equals(Object obj) {
                Point o = (Point) obj;
                return Math.abs(x - o.x) < eps && Math.abs(y - o.y) < eps;
            }

            public int compareTo(Point o) {
                if (Math.abs(x - o.x) < eps && Math.abs(y - o.y) < eps) {
                    return 0;
                }
                if (x != o.x) {
                    return x < o.x ? -1 : 1;
                }
                if (y != o.y) {
                    return y < o.y ? -1 : 1;
                }
                return 0;
            }

        }

        class Circle {
            Point o;
            double r;

            boolean contains(Point p) {
                double dist = p.sub(o).length();
                return Math.abs(dist - r) < eps;
            }

        }

    }

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

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

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

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

    }
}


import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.Random;

/**
 * Created by dalt on 2018/3/25.
 */
public class CF933C {
    static final boolean IS_OJ = System.getProperty("ONLINE_JUDGE") != null;
    public static BlockReader input;

    public static void main(String[] args) throws FileNotFoundException {
        if (!IS_OJ) {
            System.setIn(new FileInputStream("D:\\DataBase\\TESTCASE\\codeforces\\CF933C.in"));
        }
        input = new BlockReader(System.in);

        solve();
    }

    public static void solve() {
        int n = input.nextInteger();
        Circle[] circles = new Circle[n];
        for (int i = 0; i < n; i++) {
            circles[i] = new Circle(input.nextInteger(), input.nextInteger(), input.nextInteger());
        }

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

        if (n == 2) {
            System.out.println(Circle.isIntersect(circles[0], circles[1]) ? "4" : "3");
            return;
        }

        int num = Circle.isIntersect(circles[0], circles[1]) ? 4 : 3;
        num += 1; //add circle3
        if (Circle.isIntersect(circles[0], circles[2])) {
            num += 1; //if circle1 intersect with circle3
        }
        if (Circle.isIntersect(circles[1], circles[2])) {
            num += 1;
        }

        if (num == 7) {
            //Probably exists a point in the all circles
            if (sa(circles) == 3) {
                num++;
            }
        }

        System.out.println(num);
    }

    public static int sa(Circle[] circles) {
        Random random = new Random(19950823);

        Point now = new Point(0, 0);
        double nowVal = evaluate(circles, now);

        double t = 1000;
        double k = 1;
        double r = 0.98;
        while (t > 1e-5) {
            Point next = new Point(Math.max(-20, Math.min(20, now.x + nextDouble(random, -t, t))), Math.max(-20, Math.min(20, now.y + nextDouble(random, -t, t))));
            double nextVal = evaluate(circles, next);
            if (nextVal > nowVal || random.nextDouble() < Math.exp((nextVal - nowVal) / (k * t))) {
                now = next;
                nowVal = nextVal;
            }

            t *= r;
        }

        int sum = 0;
        for (Circle circle : circles) {
            if (distance(circle.center, now) < circle.r) {
                sum++;
            }
        }
        return sum;
    }

    public static double evaluate(Circle[] circles, Point point) {
        double sum = 0;
        for (Circle circle : circles) {
            double d = distance(point, circle.center);
            if (d > circle.r) {
                sum -= (d - circle.r);
            }
        }
        return sum;
    }

    public static double nextDouble(Random random, double l, double r) {
        return random.nextDouble() * (r - l) + l;
    }

    public static double distance(Point a, Point b) {
        return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
    }

    public static class Circle {
        Point center;
        int r;

        public Circle(int x, int y, int r) {
            this.center = new Point(x, y);
            this.r = r;
        }

        public static boolean isIntersect(Circle a, Circle b) {
            double d = distance(a.center, b.center);
            return d < a.r + b.r && d > Math.abs(a.r - b.r);
        }
    }

    public static class Point {
        double x, y;

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

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

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


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.PrintWriter;
import java.util.Set;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.TreeSet;
import java.util.ArrayList;
import java.util.List;
import java.util.TreeMap;
import java.util.StringTokenizer;
import java.util.Map;
import java.io.BufferedReader;
import java.util.Collections;
import java.io.InputStream;

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

    static class TaskC {
        final double eps = 1e-10;

        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            int n = in.nextInt();
            Circle[] circles = new Circle[n];
            for (int i = 0; i < n; i++) {
                int x = in.nextInt();
                int y = in.nextInt();
                int r = in.nextInt();
                circles[i] = new Circle();
                circles[i].o = new Point(x, y);
                circles[i].r = r;
            }

            Set<Point> all = new TreeSet<>();
            for (int i = 0; i < n; i++) {
                for (int j = i + 1; j < n; j++) {
                    List<Point> inter = intersect(circles[i], circles[j]);
                    if (inter == null) {
                        continue;
                    }
                    all.addAll(inter);
                }
            }

            Map<Point, Integer> pointId = new TreeMap<>();
            List<Set<Integer>> adj = new ArrayList<>();
            for (int i = 0; i < n; i++) {
                List<Double> angles = new ArrayList<>();
                final int K = 10;
                for (int j = 0; j < K; j++) {
                    angles.add(Math.PI * 2 * j / K + 1e-5);
                }
                for (Point p : all) {
                    if (circles[i].contains(p)) {
                        double dx = p.x - circles[i].o.x;
                        double dy = p.y - circles[i].o.y;
                        angles.add(Math.atan2(dy, dx));
                    }
                }
                Collections.sort(angles);
                Point dir = new Point(1, 0).scale(circles[i].r);
                for (int j = 0; j < angles.size(); j++) {
                    Point p = circles[i].o.add(dir.rotate(angles.get(j)));
                    getId(p, pointId, adj);
                }
                for (int j = 0; j < angles.size(); j++) {
                    Point p = circles[i].o.add(dir.rotate(angles.get(j)));
                    Point q = circles[i].o.add(dir.rotate(angles.get((j + 1) % angles.size())));
                    int u = pointId.get(p);
                    int v = pointId.get(q);
                    adj.get(u).add(v);
                    adj.get(v).add(u);
                }
            }

            int v = adj.size();
            int e = 0;
            for (int i = 0; i < v; i++) {
                e += adj.get(i).size();
            }
            e /= 2;

            int comps = 0;
            boolean[] was = new boolean[v];
            for (int i = 0; i < v; i++) {
                if (!was[i]) {
                    ++comps;
                    dfs(i, was, adj);
                }
            }

            out.println(1 + comps + e - v);
        }

        private void dfs(int i, boolean[] was, List<Set<Integer>> adj) {
            was[i] = true;
            for (int j : adj.get(i)) {
                if (!was[j]) {
                    dfs(j, was, adj);
                }
            }
        }

        private void getId(Point p, Map<Point, Integer> pointId, List<Set<Integer>> adj) {
            if (!pointId.containsKey(p)) {
                int sz = pointId.size();
                pointId.put(p, sz);
                adj.add(new TreeSet<>());
            }
        }

        private List<Point> intersect(Circle c1, Circle c2) {
            double dx = c1.o.x - c2.o.x;
            double dy = c1.o.y - c2.o.y;
            double d = Math.sqrt(dx * dx + dy * dy);
            double cos = (c1.r * c1.r + d * d - c2.r * c2.r) / (2 * c1.r * d);
            if (cos < -1 - eps) {
                return null;
            }
            if (cos < -1) {
                cos = -1;
            }
            if (cos > 1 + eps) {
                return null;
            }
            if (cos > 1) {
                cos = 1;
            }
            List<Point> res = new ArrayList<>();
            double alpha = Math.acos(cos);
            Point dir = c2.o.sub(c1.o).norm();
            res.add(c1.o.add(dir.scale(c1.r).rotate(+alpha)));
            res.add(c1.o.add(dir.scale(c1.r).rotate(-alpha)));
            return res;
        }

        class Point implements Comparable<Point> {
            double x;
            double y;

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

            Point add(Point o) {
                return new Point(x + o.x, y + o.y);
            }

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

            Point rotate(double alpha) {
                double c = Math.cos(alpha);
                double s = Math.sin(alpha);
                double nx = x * c - y * s;
                double ny = x * s + y * c;
                return new Point(nx, ny);
            }

            Point norm() {
                double len = length();
                return scale(1.0 / len);
            }

            Point scale(double f) {
                return new Point(f * x, f * y);
            }

            double length() {
                return Math.sqrt(x * x + y * y);
            }

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

            public boolean equals(Object obj) {
                Point o = (Point) obj;
                return Math.abs(x - o.x) < eps && Math.abs(y - o.y) < eps;
            }

            public int compareTo(Point o) {
                if (Math.abs(x - o.x) < eps && Math.abs(y - o.y) < eps) {
                    return 0;
                }
                if (x != o.x) {
                    return x < o.x ? -1 : 1;
                }
                if (y != o.y) {
                    return y < o.y ? -1 : 1;
                }
                return 0;
            }

        }

        class Circle {
            Point o;
            double r;

            boolean contains(Point p) {
                double dist = p.sub(o).length();
                return Math.abs(dist - r) < eps;
            }

        }

    }

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

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

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

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

    }
}


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

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

    static class TaskA {
        public void solve(int testNumber, FastScanner in, PrintWriter out) {
            for (int test = 1; ; test++) {
                int n = in.nextInt();
                int D = in.nextInt();
                if (n == 0 && D == 0) {
                    break;
                }
                out.println("@" + test);
                final double r = 1;
                Point pl = new Point(-D, 0);
                Point pr = new Point(+D, 0);
                for (int i = 0; i < n; i++) {
                    int sl = in.nextInt();
                    int sr = in.nextInt();
                    double vl = sl / 180.0 * Math.PI * r;
                    double vr = sr / 180.0 * Math.PI * r;
                    int t = in.nextInt();
                    if (sl == sr) {
                        Point v = pr.sub(pl).rotate(Math.PI / 2).norm().scale((vl + vr) * 0.5 * t);
                        pl = pl.add(v);
                        pr = pr.add(v);
                        continue;
                    }
                    double x = D * (vl + vr) / (vl - vr);
//                double x = D * (vl + vr) / (vr - vl);
                    Point o = pl.add(pr).scale(0.5);
                    Point ox = o.add(pr.sub(o).norm().scale(x));
//                out.println("!" + cross(ox,pr.sub(pl)));

                    Point nl = pl.sub(ox);
                    Point nr = pr.sub(ox);
//                nl=nl.scale(-1);
//                nr=nr.scale(-1);
                    double wl = vl / nl.length();
                    double wr = vr / nr.length();
//                if (x < D && x > -D) {
//                    wr = -wr;
//                }
//                out.println(wl + " " + wr);
                    nl = nl.rotate(wl * t);
                    nr = nr.rotate(wr * t);

                    pl = nl.add(ox);
                    pr = nr.add(ox);
                }
                Point p = pl.add(pr).scale(0.5);
                out.printf("%.10f\n", p.x);
                out.printf("%.10f\n", p.y);
            }
        }

        class Point {
            double x;
            double y;

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

            Point add(Point o) {
                return new Point(x + o.x, y + o.y);
            }

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

            Point rotate(double alpha) {
                double c = Math.cos(alpha);
                double s = Math.sin(alpha);
                double nx = x * c - y * s;
                double ny = x * s + y * c;
                return new Point(nx, ny);
            }

            Point norm() {
                double len = length();
                return scale(1.0 / len);
            }

            Point scale(double f) {
                return new Point(f * x, f * y);
            }

            double length() {
                return Math.sqrt(x * x + y * y);
            }

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

        }

    }

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

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

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

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

    }
}


import java.util.*;

public class susbus{
 public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
  int x = sc.nextInt();
    int y = sc.nextInt();
  int z = sc.nextInt();
  int t1 = sc.nextInt();
  int t2 = sc.nextInt();
  int t3 = sc.nextInt();
  if (t1*(Math.abs(y-x) < 2*t3+t2*Math.abs(z-y)+t1*Math.abs(z-x))){
   System.out.println("YES");
  }
  else{
   System.out.println("NO");
  }

 }
}


import java.util.*;

public class susbus{
 public static void main(String[] args){
  Scanner sc = new Scanner(System.in);
  int x = sc.nextInt();
    int y = sc.nextInt();
  int z = sc.nextInt();
  int t1 = sc.nextInt();
  int t2 = sc.nextInt();
  int t3 = sc.nextInt();
  if (t1*(Math.abs(y-x)) < t2*Math.abs(z-x)+t2*Math.abus(y-x)+4*t3){
   System.out.println("YES");
  }
  else{
   System.out.println("NO");
  }

 }
}


import java.util.*;

public class m
{
	public int stairs(int start,int end,int t1)
	{
		int t;
		t=(Math.abs(start-end))*t1;
		return t;
	}
	public int alivator(int start,int end ,int l,int t2,int t3)
	{
		int m1;
		m1=((Math.abs(start-l))*t2)+2*t3;
		int l1;
		l1=((Math.abs(start-end))*t2)+t3;
		return (m1+l1);
	}
}

public class stairs
{
	public static void main(String[] args) {
		Scanner sc=new Scanner(System.in);
		m p=new m();
		int x=sc.nextInt();
		int y=sc.nextInt();
		int z=sc.nextInt();
		int t1=sc.nextInt();
		int t2=sc.nextInt();
		int t3=sc.nextInt();
		int l1=p.stairs(x,y,t1);
		int y1=p.alivator(x,y,z,t2,t3);
		if(y1<=l1)
		{
			System.out.println("Yes");
		}
		else
		{
			System.out.println("No");
		}
	}
}


public class CodeForces2 {

    public static void main(String[] args) {
        InputStream inputStream = System.in;
        OutputStream outputStream = System.out;
        InputReader in = new InputReader(inputStream);
        PrintWriter out = new PrintWriter(outputStream);
        Task solver = new Task();
        solver.solve(1, in, out);
        out.close();
    }

    static class Task {
        public void solve(int testNumber, InputReader in, PrintWriter out) {
            int x = in.nextInt();
            int y = in.nextInt();
            int z = in.nextInt();
            int t1 = in.nextInt();
            int t2 = in.nextInt();
            int t3 = in.nextInt();

            int stairs = Math.abs(x - y) * t1;
            int ele = Math.abs(x - z) * t2 + 2 * t3 + Math.abs(y - z) * t2 + 2 * t3;

            if(stairs < ele) {
                out.println("NO");
            } else{
                out.println("YES");
            }

        }
    }

    static class InputReader {
        public 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());
        }
    }
}


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

public class p3
{
	BufferedReader br;
	StringTokenizer st;
	BufferedWriter bw;
	public static void main(String[] args)throws Exception
	{
		new p3().run();
	}

	void run()throws IOException
	{
		br = new BufferedReader(new InputStreamReader(System.in));
		bw=new BufferedWriter(new OutputStreamWriter(System.out));
		solve();
	}
	void solve() throws IOException
	{
		int t=ni();
		while(t-->0)
		{
			int n=ni();
			int m=ni();
			int k=ni();
			int q=ni();
			int d1[]=new int[q];
			int d2[]=new int[q];
			for(int i=-1;++i<q;)
			{
				d1[i]=ni();d2[i]=ni();
			}

			int x=0;
			int a[]=new int[n];
			int b[]=new int[m];

			for(int i=q;--i>=0;)
			{
				if(a[d1[i]-1]==0 || b[d2[i]-1]==0)
				{
					if(a[d1[i]-1]==0)
					{
						a[d1[i]-1]=1;
						n--;
					}
					if(b[d2[i]-1]==0)
					{
						b[d2[i]-1]=1;
						m--;
					}
					x++;
				}

				if(n==0 || m==0)
					break;
			}

			long ans=nPowerM(k, x);

			bw.write(ans+"\n");
		}
		bw.flush();
	}

	public long nPowerM(int n, int m)
	{
		if(m==0)
			return 1L;

		// int mod=1000000007;
		int mod=998244353;
		long ans=nPowerM(n, m/2);
		ans*=ans;
		ans%=mod;

		if(m%2==1)
		{
			ans*=n;
			ans%=mod;
		}

		return ans;
	}
	/////////////////////////////////////// FOR INPUT ///////////////////////////////////////

	int[] nai(int n) { int a[]=new int[n]; for(int i=-1;++i<n;)a[i]=ni();	return a;}
	Integer[] naI(int n) { Integer a[]=new Integer[n]; for(int i=-1;++i<n;)a[i]=ni();	return a;}
	long[] nal(int n) { long a[]=new long[n]; for(int i=-1;++i<n;)a[i]=nl();	return a;}
	char[] nac()	{char c[]=nextLine().toCharArray();	return c;}
	char [][] nmc(int n)	{char c[][]=new char[n][]; for(int i=-1;++i<n;)c[i]=nac();	return c;}
	int[][] nmi(int r, int c)	{int a[][]=new int[r][c]; for(int i=-1;++i<r;)a[i]=nai(c);	return a;}
	String next()
	{
			while (st == null || !st.hasMoreElements()) {
				try {st = new StringTokenizer(br.readLine());}
				catch (IOException e) {e.printStackTrace();} }
			return st.nextToken();
	}
	int ni() { return Integer.parseInt(next()); }
	byte nb() { return Byte.parseByte(next()); }
	short ns() { return Short.parseShort(next()); }
	long nl() { return Long.parseLong(next()); }
	double nd()	{	return Double.parseDouble(next());	}
	String nextLine()
	{
			String str = "";
			try {str = br.readLine();}
			catch (IOException e) {e.printStackTrace();}
			return str;
	}
}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.StringTokenizer;
public class Main {
    static class MyScanner {
        BufferedReader br;
        StringTokenizer st;

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

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

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

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

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

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

   static MyScanner s=new MyScanner();

   public static int process(int a,int k) {
	   long ans=1;
	   for(int i=0;i<a;i++)ans*=10;
	   return (int)ans%k;
   }
   static int[]arr;
   static int mod=(int)1e9+7;
   {
	   arr=new int[100010];
	   arr[0]=1;
	   for(int i=1;i<=100000;i++) {
		   arr[i]=((arr[i-1]%mod)*2)%mod;
	   }
   }
   public static long C(int n,int i) {
	  if(i>n/2)i=n-i;
	  long a=1,b=1;
	  for(int j=1;j<=i;j++) {
		  a*=(n-j+1);a%=mod;
		  b*=j;b%=mod;
		  if(a%b==0) {
			  a/=b;b=1;
		  }
	  }
	  return (a/b)%mod;
   }
public static void main(String[] args) {
int K=1;
int N=10,M=10;
while(K>0) {
    int n=s.nextInt(),k=s.nextInt();
    if(k>=n)System.out.println(arr[n]);
    long ans=0;
    for(int i=0;i<=k;i++) {
    	ans=ans%mod+C(n,i)%mod;ans%=mod;
    }
    System.out.println(ans);
	K--;
}
}
}


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

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

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

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

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

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

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

		initIO(isFileIO);

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

	    for (int i = 1; i <= t; ++i) {
	    	if(isDebug){
		    	out.printf("Test %d\n", i);
	    	}

	    	getInput();

	    	solve();

	    	printOutput();
	    }

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

	static long MOD = 1_000_000_007;

	// use suitable one between matrix(2, n), matrix(n, 2), transposedMatrix(2, n) for graph edges, pairs, ...
	int n, k;
	void getInput() {
		n = in.nextInt();
		k = in.nextInt();
	}

	void printOutput() {
		out.printlnAns(ans);
	}

	long ans;
	void solve(){
		// k >= n -> the sponsors can always make 2^n win

		// k = 1
		// at the last match, suppose 1 and 2 will match -> can make 2 win
		// but then, if we designed so that 1 would win, largest opponent that faced 1 could win
		// there are n opponents that faced 1, so the answer = n+1

		// k = 2
		// for each of those n opponents,
		// (who played 0, 1, ..., n-1 games before facing 1)
		// (n-1)n/2 more opponents appear

		long[] choose = new long[n+1];
		choose[0] = 1;
		// n!/i!/(n-i)!
		// = n!/(i-1)!/(n-i+1)!
		// nCi = nC(i-1)/i*(n-i+1)
		for(int i=1; i<=n; i++)
			choose[i] = (choose[i-1] * (n-i+1) % MOD) * inverse(i, MOD) % MOD;

		ans = 0;
		for(int i=0; i<=Math.min(k, n); i++)
			ans += choose[i];
		ans %= MOD;
	}

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

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

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

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

//	Optional<T> solve()
//	return Optional.empty();

	static class Pair implements Comparable<Pair>{
		final static long FIXED_RANDOM = System.currentTimeMillis();
		int first, second;
		public Pair(int first, int second) {
			this.first = first;
			this.second = second;
		}

		@Override
		public int hashCode() {
			// http://xorshift.di.unimi.it/splitmix64.c
			long x = first;
			x <<= 32;
			x += second;
			x += FIXED_RANDOM;
			x += 0x9e3779b97f4a7c15l;
			x = (x ^ (x >> 30)) * 0xbf58476d1ce4e5b9l;
			x = (x ^ (x >> 27)) * 0x94d049bb133111ebl;
			return (int)(x ^ (x >> 31));
		}
		@Override
		public boolean equals(Object obj) {
//			if (this == obj)
//				return true;
//			if (obj == null)
//				return false;
//			if (getClass() != obj.getClass())
//				return false;
			Pair other = (Pair) obj;
			return first == other.first && second == other.second;
		}
		@Override
		public String toString() {
			return "[" + first + "," + second + "]";
		}

		@Override
		public int compareTo(Pair o) {
			int cmp = Integer.compare(first, o.first);
			return cmp != 0? cmp: Integer.compare(second, o.second);
		}
	}

	public static class MyScanner {
		BufferedReader br;
		StringTokenizer st;

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

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

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

		}

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

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

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

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

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

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

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

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

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

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

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

		String[] nextStringArray(int len) {
			String[] s = new String[len];
			for(int i=0; i<len; i++)
				s[i] = next();
			return s;
		}
	}

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

//		public <T> void printlnAns(Optional<T> ans) {
//			if(ans.isEmpty())
//				println(-1);
//			else
//				printlnAns(ans.get());
//		}

		public void printlnAns(OptionalInt ans) {
			println(ans.orElse(-1));
		}

		public void printlnAns(long ans) {
			println(ans);
		}

		public void printlnAns(int ans) {
			println(ans);
		}

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

		return childrens;
	}

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

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

		for(int i=0; i<e.length; i++) {
			int u = e[i][0];
			int v = e[i][1];
			outNeighbors[u][--outDegree[u]] = v;
			inNeighbors[v][--inDegree[v]] = u;
		}

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

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

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

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

		return neighbors;
	}

	static private void drawGraph(int[][] e) {
		makeDotUndirected(e);
		try {
			final Process process = new ProcessBuilder("dot", "-Tpng", "graph.dot")
					.redirectOutput(new File("graph.png"))
					.start();
		} catch (IOException e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}

	}

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

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

}


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

public class Main {
    static FastReader sc=new FastReader();
	static PrintWriter out=new PrintWriter(System.out);
	static int dx[]={0,0,-1,1},dy[]={-1,1,0,0};
	static final double pi=3.1415926536;
	static long mod=1000000007;
	// static long mod=998244353;
	static int MAX=Integer.MAX_VALUE;
	static int MIN=Integer.MIN_VALUE;
	static long MAXL=Long.MAX_VALUE;
	static long MINL=Long.MIN_VALUE;
	static ArrayList<Integer> graph[];
	static long fact[];
	static long seg[];
	static int dp[];
	// static long dp[][];
	public static void main (String[] args) throws java.lang.Exception
	{
		// code goes here
		int t=I();
		outer:while(t-->0)
		{
			int n=I(),k=I();
			long nodes=pwr(2,k)-1;
			long levels=n-k;
			out.println(nodes*pwr(2,levels)+1);
		}
		out.close();
	}
	public static class pair
    {
    	int a;
    	int b;
    	public pair(int aa,int bb)
    	{
    	    a=aa;
    	    b=bb;
    	}
    }
	public static class myComp implements Comparator<pair>
	{
		//sort in ascending order.
		public int compare(pair p1,pair p2)
		{
			if(p1.a==p2.a)
    	    return 0;
    	    else if(p1.a<p2.a)
    	    return -1;
    	    else
    	    return 1;
		}
		// sort in descending order.
		// public int compare(pair p1,pair p2)
    	// {
    	//     if(p1.b==p2.b)
    	//     return 0;
    	//     else if(p1.b<p2.b)
    	//     return 1;
    	//     else
    	//     return -1;
    	// }
	}
	public static void setGraph(int n,int m)throws IOException
	{
		graph=new ArrayList[n+1];
		for(int i=0;i<=n;i++){
			graph[i]=new ArrayList<>();
		}
		for(int i=0;i<m;i++){
			int u=I(),v=I();
			graph[u].add(v);
			graph[v].add(u);
		}
	}

	//LOWER_BOUND and UPPER_BOUND functions

	//It returns answer according to zero based indexing.
	public static int lower_bound(pair[] arr,int X,int start, int end)   //start=0,end=n-1
	{
		if(start>end)return -1;
		// if(arr.get(end)<X)return end;
		if(arr[end].a<X)return end;
		// if(arr.get(start)>X)return -1;
		if(arr[start].a>X)return -1;
		int left=start,right=end;
		while(left<right){
			int mid=(left+right)/2;

			if(arr[mid].a==X){
			// if(arr.get(mid)==X){                                    //Returns last index of lower bound value.
				if(mid<end && arr[mid+1].a==X){
				// if(mid<end && arr.get(mid+1)==X){
					left=mid+1;
				}else{
					return mid;
				}
			}

			// if(arr.get(mid)==X){                                   //Returns first index of lower bound value.
			// if(arr[mid]==X){
			// 	// if(mid>start && arr.get(mid-1)==X){
			// 	if(mid>start && arr[mid-1]==X){
			// 		right=mid-1;
			// 	}else{
			// 		return mid;
			// 	}
			// }

			else if(arr[mid].a>X){
			// else if(arr.get(mid)>X){
				if(mid>start && arr[mid-1].a<X){
				// if(mid>start && arr.get(mid-1)<X){
					return mid-1;
				}else{
					right=mid-1;
				}
			}else{
				if(mid<end && arr[mid+1].a>X){
				// if(mid<end && arr.get(mid+1)>X){
					return mid;
				}else{
					left=mid+1;
				}
			}
		}
		return left;
	}
	//It returns answer according to zero based indexing.
	public static int upper_bound(long arr[],long X,int start,int end)			//start=0,end=n-1
	{
		if(arr[0]>=X)return start;
		if(arr[arr.length-1]<X)return -1;
		int left=start,right=end;
		while(left<right){
			int mid=(left+right)/2;
			if(arr[mid]==X){                                   //returns first index of upper bound value.
				if(mid>start && arr[mid-1]==X){
					right=mid-1;
				}else{
					return mid;
				}
			}
			// if(arr[mid]==X){									//returns last index of upper bound value.
			// 	if(mid<end && arr[mid+1]==X){
			// 		left=mid+1;
			// 	}else{
			// 		return mid;
			// 	}
			// }
			else if(arr[mid]>X){
				if(mid>start && arr[mid-1]<X){
					return mid;
				}else{
					right=mid-1;
				}
			}else{
				if(mid<end && arr[mid+1]>X){
					return mid+1;
				}else{
					left=mid+1;
				}
			}
		}
		return left;
	}

	//END

	//Segment Tree Code
	public static void buildTree(long a[],int si,int ss,int se)
	{
		if(ss==se){
			seg[si]=a[ss];
			return;
		}
		int mid=(ss+se)/2;
		buildTree(a,2*si+1,ss,mid);
		buildTree(a,2*si+2,mid+1,se);
		seg[si]=max(seg[2*si+1],seg[2*si+2]);
	}
	// public static void update(int si,int ss,int se,int pos,int val)
	// {
	// 	if(ss==se){
	// 		// seg[si]=val;
	// 		return;
	// 	}
	// 	int mid=(ss+se)/2;
	// 	if(pos<=mid){
	// 		update(2*si+1,ss,mid,pos,val);
	// 	}else{
	// 		update(2*si+2,mid+1,se,pos,val);
	// 	}
	// 	// seg[si]=min(seg[2*si+1],seg[2*si+2]);
	// 	if(seg[2*si+1].a < seg[2*si+2].a){
	// 		seg[si].a=seg[2*si+1].a;
	// 		seg[si].b=seg[2*si+1].b;
	// 	}else{
	// 		seg[si].a=seg[2*si+2].a;
	// 		seg[si].b=seg[2*si+2].b;
	// 	}
	// }
	public static long query(int si,int ss,int se,int qs,int qe)
	{
		if(qs>se || qe<ss)return 0;
		if(ss>=qs && se<=qe)return seg[si];
		int mid=(ss+se)/2;
		long p1=query(2*si+1,ss,mid,qs,qe);
		long p2=query(2*si+2,mid+1,se,qs,qe);
		return max(p1,p2);

	}

	public static void merge(ArrayList<Integer> f,ArrayList<Integer> a,ArrayList<Integer> b)
	{
		int i=0,j=0;
		while(i<a.size() && j<b.size()){
			if(a.get(i)<=b.get(j)){
				f.add(a.get(i));
				i++;
			}else{
				f.add(b.get(j));
				j++;
			}
		}
		while(i<a.size()){
			f.add(a.get(i));
			i++;
		}
		while(j<b.size()){
			f.add(b.get(j));
			j++;
		}
	}

	//Segment Tree Code end

	//Prefix Function of KMP Algorithm
	public static int[] KMP(char c[],int n)
	{
		int pi[]=new int[n];
		for(int i=1;i<n;i++){
			int j=pi[i-1];
			while(j>0 && c[i]!=c[j]){
				j=pi[j-1];
			}
			if(c[i]==c[j])j++;
			pi[i]=j;
		}
		return pi;
	}
	public static long kadane(long a[],int n)  //largest sum subarray
	{
		long max_sum=Long.MIN_VALUE,max_end=0;
		for(int i=0;i<n;i++){
			max_end+=a[i];
			if(max_sum<max_end){max_sum=max_end;}
			if(max_end<0){max_end=0;}
		}
		return max_sum;
	}

	public static ArrayList<Long> primeFact(long x)
	{
		ArrayList<Long> arr=new ArrayList<>();
		if(x%2==0){
			arr.add(2L);
			while(x%2==0){
				x/=2;
			}
		}
		for(long i=3;i*i<=x;i+=2){
			if(x%i==0){
				arr.add(i);
				while(x%i==0){
					x/=i;
				}
			}
		}
		if(x>0){
			arr.add(x);
		}
		return arr;
	}
	public static long nPr(int n,int r)
	{
		long ans=divide(fact(n),fact(n-r),mod);
		return ans;
	}
	public static long nCr(int n,int r)
	{
		long ans=divide(fact[n],mul(fact[n-r],fact[r]),mod);
		return ans;
	}

	public static boolean isSorted(int a[])
	{
		int n=a.length;
		for(int i=0;i<n-1;i++){
			if(a[i]>a[i+1])return false;
		}
		return true;
	}
	public static boolean isSorted(long a[])
	{
		int n=a.length;
		for(int i=0;i<n-1;i++){
			if(a[i]>a[i+1])return false;
		}
		return true;
	}
	public static long toggleBits(long x)//one's complement || Toggle bits
	{
		int n=(int)(Math.floor(Math.log(x)/Math.log(2)))+1;

		return ((1<<n)-1)^x;
	}
	public static int computeXOR(int n) //compute XOR of all numbers between 1 to n.
    {
        if (n % 4 == 0)
            return n;
        if (n % 4 == 1)
            return 1;
        if (n % 4 == 2)
            return n + 1;
        return 0;
    }
	public static int np2(int x)
	{
		x--;
		x |= x >> 1;
		x |= x >> 2;
		x |= x >> 4;
		x |= x >> 8;
		x |= x >> 16;
		x++;
		return x;
	}
	public static int hp2(int x)
	{
		x |= x >> 1;
		x |= x >> 2;
		x |= x >> 4;
		x |= x >> 8;
		x |= x >> 16;
		return x ^ (x >> 1);
	}
	public static long hp2(long x)
	{
		x |= x >> 1;
		x |= x >> 2;
		x |= x >> 4;
		x |= x >> 8;
		x |= x >> 16;
		return x ^ (x >> 1);
	}
	public static ArrayList<Integer> primeSieve(int n)
	{
	    ArrayList<Integer> arr=new ArrayList<>();
	    boolean prime[] = new boolean[n + 1];
        for (int i = 0; i <= n; i++)
        prime[i] = true;
        for (int p = 2; p * p <= n; p++)
        {
            if (prime[p] == true)
            {
                for (int i = p * p; i <= n; i += p)
                prime[i] = false;
            }
        }
        for (int i = 2; i <= n; i++)
        {
            if (prime[i] == true)
            arr.add(i);
        }
        return arr;
	}

	// Fenwick / BinaryIndexed  Tree  USE IT - FenwickTree ft1=new FenwickTree(n);
	public static class FenwickTree
	{
		int farr[];
		int n;
		public FenwickTree(int c)
		{
			n=c+1;
			farr=new int[n];
		}
		// public void update_range(int l,int r,long p)
		// {
		// 	update(l,p);
		// 	update(r+1,(-1)*p);
		// }
		public void update(int x,int p)
		{
			for(;x<n;x+=x&(-x))
			{
				farr[x]+=p;
			}
		}
		public int get(int x)
		{
			int ans=0;
			for(;x>0;x-=x&(-x))
			{
				ans=ans+farr[x];
			}
			return ans;
		}
	}
	//Disjoint Set Union

	//NOTE: call find function for all the index in the par array at last,
	//in order to set parent of every index properly.
	public static class DSU
	{
	    int par[],rank[];
	    public DSU(int c)
	    {
	        par=new int[c+1];
	        rank=new int[c+1];
	        for(int i=0;i<=c;i++)
	        {
	            par[i]=i;
	            rank[i]=0;
	        }
	    }
	    public int find(int a)
	    {
	        if(a==par[a])
	        return a;
	        return par[a]=find(par[a]);
	    }
	    public void union(int a,int b)
	    {
	        int a_rep=find(a),b_rep=find(b);
	        if(a_rep==b_rep)
	        return;
	        if(rank[a_rep]<rank[b_rep])
	        par[a_rep]=b_rep;
	        else if(rank[a_rep]>rank[b_rep])
	        par[b_rep]=a_rep;
	        else
	        {
	            par[b_rep]=a_rep;
	            rank[a_rep]++;
	        }
	    }
	}
	public static boolean isVowel(char c)
	{
		if(c=='a' || c=='e' || c=='i' || c=='u' || c=='o')return true;
		return false;
	}
	public static boolean isInteger(double N)
	{
		int X = (int)N;
		double temp2 = N - X;
		if (temp2 > 0)
		{
			return false;
		}
		return true;
	}
	public static boolean isPalindrome(String s)
	{
		int n=s.length();
		for(int i=0;i<=n/2;i++){
			if(s.charAt(i)!=s.charAt(n-i-1)){
				return false;
			}
		}
		return true;
	}
	public static int gcd(int a,int b)
	{
	    if(b==0)
	    return a;
	    else
	    return gcd(b,a%b);
	}
	public static long gcd(long a,long b)
	{
	    if(b==0)
	    return a;
	    else
	    return gcd(b,a%b);
	}
	public static long fact(long n)
	{
		long fact=1;
		for(long i=2;i<=n;i++){
			fact=((fact%mod)*(i%mod))%mod;
		}
		return fact;
	}
	public static long fact(int n)
	{
		long fact=1;
		for(int i=2;i<=n;i++){
			fact=((fact%mod)*(i%mod))%mod;
		}
		return fact;
	}
	public static boolean isPrime(int n)
	{
	    if (n <= 1)
	        return false;
	    if (n <= 3)
	        return true;
	    if (n % 2 == 0 || n % 3 == 0)
	        return false;
	    double sq=Math.sqrt(n);

	    for (int i = 5; i <= sq; i = i + 6)
	        if (n % i == 0 || n % (i + 2) == 0)
	            return false;
	    return true;
	}
    public static boolean isPrime(long n)
	{
	    if (n <= 1)
	        return false;
	    if (n <= 3)
	        return true;
	    if (n % 2 == 0 || n % 3 == 0)
	        return false;
	    double sq=Math.sqrt(n);

	    for (int i = 5; i <= sq; i = i + 6)
	        if (n % i == 0 || n % (i + 2) == 0)
	            return false;
	    return true;
	}
	public static void printArray(long a[])
	{
		for(int i=0;i<a.length;i++){
			out.print(a[i]+" ");
		}
		out.println();
	}
	public static void printArray(int a[])
	{
		for(int i=0;i<a.length;i++){
			out.print(a[i]+" ");
		}
		out.println();
	}
	public static void printArray(char a[])
	{
		for(int i=0;i<a.length;i++){
			out.print(a[i]);
		}
		out.println();
	}
	public static void printArray(String a[])
	{
		for(int i=0;i<a.length;i++){
			out.print(a[i]+" ");
		}
		out.println();
	}
	public static void printArray(boolean a[])
	{
		for(int i=0;i<a.length;i++){
			out.print(a[i]+" ");
		}
		out.println();
	}
	public static void printArray(pair a[])
	{
		for(pair p:a){
			out.println(p.a+"->"+p.b);
		}
	}
	public static void printArray(int a[][])
	{
		for(int i=0;i<a.length;i++){
			for(int j=0;j<a[i].length;j++){
				out.print(a[i][j]+" ");
			}out.println();
		}
	}
	public static void printArray(String a[][])
	{
		for(int i=0;i<a.length;i++){
			for(int j=0;j<a[i].length;j++){
				out.print(a[i][j]+" ");
			}out.println();
		}
	}
	public static void printArray(boolean a[][])
	{
		for(int i=0;i<a.length;i++){
			for(int j=0;j<a[i].length;j++){
				out.print(a[i][j]+" ");
			}out.println();
		}
	}
	public static void printArray(long a[][])
	{
		for(int i=0;i<a.length;i++){
			for(int j=0;j<a[i].length;j++){
				out.print(a[i][j]+" ");
			}out.println();
		}
	}
	public static void printArray(char a[][])
	{
		for(int i=0;i<a.length;i++){
			for(int j=0;j<a[i].length;j++){
				out.print(a[i][j]+" ");
			}out.println();
		}
	}
	public static void printArray(ArrayList<?> arr)
	{
		for(int i=0;i<arr.size();i++){
			out.print(arr.get(i)+" ");
		}
		out.println();
	}
	public static void printMapI(HashMap<?,?> hm){
		for(Map.Entry<?,?> e:hm.entrySet()){
			out.println(e.getKey()+"->"+e.getValue());
		}out.println();
	}
	public static void printMap(HashMap<Long,ArrayList<Integer>> hm){
		for(Map.Entry<Long,ArrayList<Integer>> e:hm.entrySet()){
			out.print(e.getKey()+"->");
			ArrayList<Integer> arr=e.getValue();
			for(int i=0;i<arr.size();i++){
				out.print(arr.get(i)+" ");
			}out.println();
		}
	}
	public static void printGraph(ArrayList<Integer> graph[])
	{
		int n=graph.length;
		for(int i=0;i<n;i++){
			out.print(i+"->");
			for(int j:graph[i]){
				out.print(j+" ");
			}out.println();
		}
	}

	//Modular Arithmetic

	public static long add(long a,long b)
	{
		a+=b;
		if(a>=mod)a-=mod;
		return a;
	}
	public static long sub(long a,long b)
	{
		a-=b;
		if(a<0)a+=mod;
		return a;
	}
	public static long mul(long a,long b)
	{
		return ((a%mod)*(b%mod))%mod;
	}
	public static long divide(long a,long b,long m)
	{
		a=mul(a,modInverse(b,m));
		return a;
	}
	public static long modInverse(long a,long m)
	{
		int x=0,y=0;
		own p=new own(x,y);
		long g=gcdExt(a,m,p);
		if(g!=1){
			out.println("inverse does not exists");
			return -1;
		}else{
			long res=((p.a%m)+m)%m;
			return res;
		}
	}
	public static long gcdExt(long a,long b,own p)
	{
		if(b==0){
			p.a=1;
			p.b=0;
			return a;
		}
		int x1=0,y1=0;
		own p1=new own(x1,y1);
		long gcd=gcdExt(b,a%b,p1);
		p.b=p1.a - (a/b) * p1.b;
		p.a=p1.b;
		return gcd;
	}
	public static long pwr(long m,long n)
	{
		long res=1;
		if(m==0)
		return 0;
		while(n>0)
		{
			if((n&1)!=0)
			{
				res=(res*m);
			}
			n=n>>1;
			m=(m*m);
		}
		return res;
	}
	public static long modpwr(long m,long n)
	{
		long res=1;
		m=m%mod;
		if(m==0)
		return 0;
		while(n>0)
		{
			if((n&1)!=0)
			{
				res=(res*m)%mod;
			}
			n=n>>1;
			m=(m*m)%mod;
		}
		return res;
	}
	public static class own
    {
    	long a;
    	long b;
    	public own(long val,long index)
    	{
    	    a=val;
    	    b=index;
    	}
    }

	//Modular Airthmetic

	public static void sort(int[] A)
	{
        int n = A.length;
        Random rnd = new Random();
        for(int i=0; i<n; ++i)
		{
            int tmp = A[i];
            int randomPos = i + rnd.nextInt(n-i);
            A[i] = A[randomPos];
            A[randomPos] = tmp;
        }
        Arrays.sort(A);
    }
	public static void sort(char[] A)
	{
        int n = A.length;
        Random rnd = new Random();
        for(int i=0; i<n; ++i)
		{
            char tmp = A[i];
            int randomPos = i + rnd.nextInt(n-i);
            A[i] = A[randomPos];
            A[randomPos] = tmp;
        }
        Arrays.sort(A);
    }
    public static void sort(long[] A)
	{
	    int n = A.length;
        Random rnd = new Random();
        for(int i=0; i<n; ++i)
		{
            long tmp = A[i];
            int randomPos = i + rnd.nextInt(n-i);
            A[i] = A[randomPos];
            A[randomPos] = tmp;
        }
	    Arrays.sort(A);
	}

	//max,min,sum and sqrt
	public static int max(int a,int b){return Math.max(a,b);}
	public static int min(int a,int b){return Math.min(a,b);}
	public static int max(int a,int b,int c){return Math.max(a,Math.max(b,c));}
	public static int min(int a,int b,int c){return Math.min(a,Math.min(b,c));}
	public static long max(long a,long b){return Math.max(a,b);}
	public static long min(long a,long b){return Math.min(a,b);}
	public static long max(long a,long b,long c){return Math.max(a,Math.max(b,c));}
	public static long min(long a,long b,long c){return Math.min(a,Math.min(b,c));}
	public static int maxinA(int a[]){int n=a.length;int mx=a[0];for(int i=1;i<n;i++){mx=max(mx,a[i]);}return mx;}
	public static long maxinA(long a[]){int n=a.length;long mx=a[0];for(int i=1;i<n;i++){mx=max(mx,a[i]);}return mx;}
	public static int mininA(int a[]){int n=a.length;int mn=a[0];for(int i=1;i<n;i++){mn=min(mn,a[i]);}return mn;}
	public static long mininA(long a[]){int n=a.length;long mn=a[0];for(int i=1;i<n;i++){mn=min(mn,a[i]);}return mn;}
	public static long suminA(int a[]){int n=a.length;long sum=0;for(int i=0;i<n;i++){sum+=a[i];}return sum;}
	public static long suminA(long a[]){int n=a.length;long sum=0;for(int i=0;i<n;i++){sum+=a[i];}return sum;}
	public static int sqrt(int a){int p=(int)Math.sqrt(a);if(p*p>a)p--;return p;}
	public static long sqrt(long a){long p=(long)Math.sqrt(a);if(p*p>a)p--;return p;}
	//end

	public static int[] I(int n)throws IOException{int a[]=new int[n];for(int i=0;i<n;i++){a[i]=I();}return a;}
	public static long[] IL(int n)throws IOException{long a[]=new long[n];for(int i=0;i<n;i++){a[i]=L();}return a;}
	public static long[] prefix(int a[]){int n=a.length;long pre[]=new long[n];pre[0]=a[0];for(int i=1;i<n;i++){pre[i]=pre[i-1]+a[i];}return pre;}
	public static long[] prefix(long a[]){int n=a.length;long pre[]=new long[n];pre[0]=a[0];for(int i=1;i<n;i++){pre[i]=pre[i-1]+a[i];}return pre;}

	public static int I()throws IOException{return sc.I();}
    public static long L()throws IOException{return sc.L();}
    public static String S()throws IOException{return sc.S();}
    public static double D()throws IOException{return sc.D();}
}
class FastReader {
    BufferedReader br;
    StringTokenizer st;
    public FastReader(){
        br = new BufferedReader(new InputStreamReader(System.in));
    }
    String next(){
        while (st == null || !st.hasMoreElements()){
            try {
                st = new StringTokenizer(br.readLine());
            }
            catch (IOException e){
                e.printStackTrace();
            }
        }
        return st.nextToken();
    }
    int I(){ return Integer.parseInt(next());}
    long L(){ return Long.parseLong(next());}
    double D(){return Double.parseDouble(next());}
    String S(){
        String str = "";
        try {
            str = br.readLine();
        }
        catch (IOException e){
            e.printStackTrace();
        }
        return str;
    }
}


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

public class E {

    final long MOD = 1_000_000_007;

    public void solve() {
        int n = in.nextInt(), k = in.nextInt();
        if (k * 2 > n) {
            out.println(0);
            return;
        }
        long[][] dp1 = new long[n + 1][k + 1], dp2 = new long[n + 1][k + 1];
        dp1[1][0] = 1;

        long[][] choose = new long[n + 1][n + 1];
        choose[0][0] = 1;
        for (int i = 1; i <= n; i++) {
            choose[i][0] = 1;
            for (int j = 1; j <= n; j++) {
                choose[i][j] = (choose[i - 1][j - 1] + choose[i - 1][j]) % MOD;
            }
        }

        for (int i = 2; i <= n; i++) {
            for (int j = 0; j <= k; j++) {

                // 1 child
                dp1[i][j] += dp2[i - 1][j] * (i - 1);
                dp1[i][j] %= MOD;
                if (j > 0) {
                    dp2[i][j] += dp1[i - 1][j - 1] * (i - 1);
                    dp2[i][j] %= MOD;
                }

                // 2 children
                for (int size1 = 1; size1 < (i - 1) - size1; size1++) {
                    for (int match1 = 0; match1 <= j; match1++) {
                        long add = dp2[size1][match1] * dp2[i - 1 - size1][j - match1] % MOD;
                        dp1[i][j] = (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp1[i][j] %= MOD;
                    }
                }
                for (int size1 = 1; size1 < (i - 1) - size1; size1++) {
                    for (int match1 = 0; match1 <= j - 1; match1++) {
                        long add = (dp1[size1][match1] * dp1[i - 1 - size1][j - 1 - match1]
                                + dp1[size1][match1] * dp2[i - 1 - size1][j - 1 - match1]
                                + dp2[size1][match1] * dp1[i - 1 - size1][j - 1 - match1]) % MOD;
                        dp2[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp2[i][j] %= MOD;
                    }
                }

                // 2 children of equal size
                if ((i - 1) % 2 == 0) {
                    int size1 = (i - 1) / 2;

                    for (int match1 = 0; match1 < j - match1; match1++ ){
                        long add = dp2[size1][match1] * dp2[size1][j - match1] % MOD;
                        dp1[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp1[i][j] %= MOD;
                    }
                    if (j % 2 == 0) {
                        int match1 = j / 2;
                        long add = (dp2[size1][match1] * (dp2[size1][match1] - 1) / 2) % MOD;
                        dp1[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp1[i][j] %= MOD;

                        add = dp2[size1][match1];
                        add = (add * (i - 1) * (i - 2) / 2) % MOD;
                        add = (add * choose[i - 3][size1 - 1]) % MOD;
                        dp1[i][j] += add;
                        dp1[i][j] %= MOD;
                    }

                    for (int match1 = 0; match1 < j - 1 - match1; match1++) {
                        long add = (dp1[size1][match1] * dp1[size1][j - 1 - match1]
                                + dp1[size1][match1] * dp2[size1][j - 1 - match1]
                                + dp2[size1][match1] * dp1[size1][j - 1 - match1]) % MOD;
                        dp2[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp2[i][j] %= MOD;
                    }

                    if ((j - 1) % 2 == 0) {
                        int match1 = (j - 1) / 2;
                        long add = (dp1[size1][match1] * dp2[size1][match1]) % MOD;
                        dp2[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp2[i][j] %= MOD;

                        add = (dp1[size1][match1] * (dp1[size1][match1] - 1) / 2) % MOD;
                        dp2[i][j] += (add * choose[i - 1][size1]) % MOD * size1 * (i - 1 - size1);
                        dp2[i][j] %= MOD;

                        add = dp1[size1][match1];
                        add = (add * (i - 1) * (i - 2) / 2) % MOD;
                        add = (add * choose[i - 3][size1 - 1]) % MOD;
                        dp2[i][j] += add;
                        dp2[i][j] %= MOD;
                    }
                }
            }
        }

        out.println((dp1[n][k] + dp2[n][k]) % MOD);
    }

    FastScanner in;
    PrintWriter out;

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

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

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

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

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

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

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

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

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


import sun.misc.Compare;

import java.io.*;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;

import java.math.BigInteger;

import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;

public class Main{

    void run(){
        Locale.setDefault(Locale.US);
        boolean oj = System.getProperty("ONLINE_JUDGE") != null;
//        boolean oj = true;
        try{
            if( oj ){
                sc  = new FastScanner( new InputStreamReader(System.in  ) );
                out = new PrintWriter(   new OutputStreamWriter(System.out) );
            } else{
                sc  = new FastScanner(new FileReader("in.txt") );
//                sc  = new FastScanner(new FileReader("D:\\JavaOlymp\\FatalError\\output.txt") );
                out = new PrintWriter(   new FileWriter("out.txt") );
            }
        } catch (Exception e) {
            System.exit(-1);
        }
        long tB = System.currentTimeMillis();
        solve();
        if( !oj ) System.err.println( "Time: " + (System.currentTimeMillis()-tB)/1e3 );
        out.flush();
    }

    class FastScanner{
        BufferedReader br;
        StringTokenizer st = new StringTokenizer("");
        FastScanner( InputStreamReader a ){
            br = new BufferedReader(a);
        }
        FastScanner( FileReader a ){
            br = new BufferedReader(a);
        }
        String next(){
            while( !st.hasMoreTokens() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    return null;
                }
            return st.nextToken();
        }
        String readLine(){
            try {
                return br.readLine();
            } catch (Exception e) {
                return null;
            }
        }
        int nextInt(){ return Integer.parseInt(next()); }
        long nextLong(){ return Long.parseLong(next()); }
    }

    FastScanner sc;
    PrintWriter out;

    public static void main(String[] args){
        new Main().run();
//        new Thread( null, new Runnable() {
//            @Override
//            public void run() {
//                new Main().run();
//            }
//            }, "LOL", 256L * 1024 * 1024 / 2 ).run();
//        }, "LOL", 2000 * 1024 * 1024 ).run();
    }

    void TLE(){ for(;;); }

    void MLE(){
        int[][] adj = new int[1024*1024][];
        for( int i = 0; i < adj.length; ++i )
            adj[i] = new int[1024*1024];
    }

    void exit( int val ){
        out.flush();
        System.exit(val);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    long[][][] dp;
    final long inf = Long.MAX_VALUE / 1000,
        mod = 1000000007 ;

    BigInteger fact( int n ){
        return n<=1? ONE : valueOf(n).multiply(fact(n-1));
    }

    long C( int m, int n ){
        if(!( m <= n )) MLE();
        return fact(n).divide( fact(m).multiply(fact(n-m)) ).mod(valueOf(mod)).longValue();
    }

    long powMod( long a, long p ){
        if( p == 0 ) return 1;
        long ans = powMod(a,p/2);
        ans = (ans*ans) % mod;
        if( p%2==1 ) ans = (a*ans) % mod;
        return ans;
    }

    long getDP( int n, int k, int isNeed ){
        if (n <= 0 || k < 0) return 0;

        if( dp[n][k][isNeed] == inf ){
            long ans = 0;

            if( n == 1 ){
                if( k==0 && isNeed == 0 )
                    ans = 1;
                else
                    ans = 0;
            }
            else{
                for( int nl = 1; nl <= n-2; ++nl ){
                for( int kl = 0; kl <= (isNeed==1?k-1:k); ++kl ){
                    long cur = (C(nl,n-1) * n) % mod;
                    if( isNeed==1 ){
                        cur *=
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 1) +
                            getDP(nl, kl, 1)*getDP(n-1-nl, k-1-kl, 0) +
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 0);
                    }
                    else{
                        cur *=
                            getDP(nl,kl,1)*getDP(n-1-nl,k-kl,1);
                    }
                    ans = (ans + cur) % mod;
                    if( n==3 ){
                        n = 3;
//                        out.printf( ":: %d/%d   %d/%d  %d\n", nl,n,   kl,k, isNeed );
                    }
                }
                }
                ans = ans * powMod(2,mod-2) % mod;
                if( isNeed == 1 )
                    ans = ( ans + n*getDP(n-1,k-1,0) ) %mod;
                else
                    ans = ( ans + n*getDP(n-1,k  ,1) ) %mod;
            }
            dp[n][k][isNeed] = ans;
        }
        return dp[n][k][isNeed];
    }

    void solve(){
        int n, k;

        n = sc.nextInt();
        k = sc.nextInt();
        dp = new long[n+1][k+1][2];
        for( long[][] a : dp )
            for( long[] b : a )
                fill( b, inf );

        long ans = getDP(n, k, 0) + getDP(n, k, 1);
        ans %= mod;
        ans = ans * powMod( n, mod - 2 ) % mod;
        out.println( ans );
    }

}


import sun.misc.Compare;

import java.io.*;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;

import java.math.BigInteger;

import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;

public class Main{

    void run(){
        Locale.setDefault(Locale.US);
        boolean oj = System.getProperty("ONLINE_JUDGE") != null;
//        boolean oj = true;
        try{
            if( oj ){
                sc  = new FastScanner( new InputStreamReader(System.in  ) );
                out = new PrintWriter(   new OutputStreamWriter(System.out) );
            } else{
                sc  = new FastScanner(new FileReader("in.txt") );
//                sc  = new FastScanner(new FileReader("D:\\JavaOlymp\\FatalError\\output.txt") );
                out = new PrintWriter(   new FileWriter("out.txt") );
            }
        } catch (Exception e) {
            System.exit(-1);
        }
        long tB = System.currentTimeMillis();
        solve();
        if( !oj ) System.err.println( "Time: " + (System.currentTimeMillis()-tB)/1e3 );
        out.flush();
    }

    class FastScanner{
        BufferedReader br;
        StringTokenizer st = new StringTokenizer("");
        FastScanner( InputStreamReader a ){
            br = new BufferedReader(a);
        }
        FastScanner( FileReader a ){
            br = new BufferedReader(a);
        }
        String next(){
            while( !st.hasMoreTokens() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    return null;
                }
            return st.nextToken();
        }
        String readLine(){
            try {
                return br.readLine();
            } catch (Exception e) {
                return null;
            }
        }
        int nextInt(){ return Integer.parseInt(next()); }
        long nextLong(){ return Long.parseLong(next()); }
    }

    FastScanner sc;
    PrintWriter out;

    public static void main(String[] args){
        new Main().run();
//        new Thread( null, new Runnable() {
//            @Override
//            public void run() {
//                new Main().run();
//            }
//            }, "LOL", 256L * 1024 * 1024 / 2 ).run();
//        }, "LOL", 2000 * 1024 * 1024 ).run();
    }

    void TLE(){ for(;;); }

    void MLE(){
        int[][] adj = new int[1024*1024][];
        for( int i = 0; i < adj.length; ++i )
            adj[i] = new int[1024*1024];
    }

    void exit( int val ){
        out.flush();
        System.exit(val);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    long[][][] dp;
    final long inf = Long.MAX_VALUE / 1000,
        mod = 1000000007 ;

    BigInteger fact( int n ){
        return n<=1? ONE : valueOf(n).multiply(fact(n-1));
    }

    long C( int m, int n ){
        if(!( m <= n )) MLE();
        return fact(n).divide( fact(m).multiply(fact(n-m)) ).mod(valueOf(mod)).longValue();
    }

    long powMod( long a, long p ){
        if( p == 0 ) return 1;
        long ans = powMod(a,p/2);
        ans = (ans*ans) % mod;
        if( p%2==1 ) ans = (a*ans) % mod;
        return ans;
    }

    long getDP( int n, int k, int isNeed ){
        if (n <= 0 || k < 0) return 0;

        if( dp[n][k][isNeed] == inf ){
            long ans = 0;

            if( n == 1 ){
                if( k==0 && isNeed == 0 )
                    ans = 1;
                else
                    ans = 0;
            }
            else{
                for( int nl = 1; nl <= n-2; ++nl ){
                for( int kl = 0; kl <= min( nl/2, (isNeed==1?k-1:k)); ++kl ){
                    long cur = (C(nl,n-1) * n) % mod;
                    if( isNeed==1 ){
                        cur *=(
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 1) +
                            getDP(nl, kl, 1)*getDP(n-1-nl, k-1-kl, 0) +
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 0)
                        ) % mod;
                    }
                    else{
                        cur *=
                            getDP(nl,kl,1)*getDP(n-1-nl,k-kl,1) % mod;
                    }
                    ans = (ans + cur) % mod;
                    if( n==3 ){
                        n = 3;
//                        out.printf( ":: %d/%d   %d/%d  %d\n", nl,n,   kl,k, isNeed );
                    }
                }
                }
                ans = ans * powMod(2,mod-2) % mod;
                if( isNeed == 1 )
                    ans = ( ans + n*getDP(n-1,k-1,0) ) %mod;
                else
                    ans = ( ans + n*getDP(n-1,k  ,1) ) %mod;
            }
            dp[n][k][isNeed] = ans;
        }
        return dp[n][k][isNeed];
    }

    void solve(){
        int n, k;

        n = sc.nextInt();
        k = sc.nextInt();
        dp = new long[n+1][k+1][2];
        for( long[][] a : dp )
            for( long[] b : a )
                fill( b, inf );

        long ans = getDP(n, k, 0) + getDP(n, k, 1);
        ans %= mod;
        ans = ans * powMod( n, mod - 2 ) % mod;
        out.println( ans );
    }

}


import sun.misc.Compare;

import java.io.*;
import java.lang.reflect.Array;
import java.math.BigDecimal;
import java.util.*;

import java.math.BigInteger;

import static java.lang.Math.*;
import static java.math.BigInteger.*;
import static java.util.Arrays.*;

public class Main{

    void run(){
        Locale.setDefault(Locale.US);
        boolean oj = System.getProperty("ONLINE_JUDGE") != null;
//        boolean oj = true;
        try{
            if( oj ){
                sc  = new FastScanner( new InputStreamReader(System.in  ) );
                out = new PrintWriter(   new OutputStreamWriter(System.out) );
            } else{
                sc  = new FastScanner(new FileReader("in.txt") );
//                sc  = new FastScanner(new FileReader("D:\\JavaOlymp\\FatalError\\output.txt") );
                out = new PrintWriter(   new FileWriter("out.txt") );
            }
        } catch (Exception e) {
            System.exit(-1);
        }
        long tB = System.currentTimeMillis();
        solve();
        if( !oj ) System.err.println( "Time: " + (System.currentTimeMillis()-tB)/1e3 );
        out.flush();
    }

    class FastScanner{
        BufferedReader br;
        StringTokenizer st = new StringTokenizer("");
        FastScanner( InputStreamReader a ){
            br = new BufferedReader(a);
        }
        FastScanner( FileReader a ){
            br = new BufferedReader(a);
        }
        String next(){
            while( !st.hasMoreTokens() )
                try {
                    st = new StringTokenizer(br.readLine());
                } catch (IOException e) {
                    return null;
                }
            return st.nextToken();
        }
        String readLine(){
            try {
                return br.readLine();
            } catch (Exception e) {
                return null;
            }
        }
        int nextInt(){ return Integer.parseInt(next()); }
        long nextLong(){ return Long.parseLong(next()); }
    }

    FastScanner sc;
    PrintWriter out;

    public static void main(String[] args){
        new Main().run();
//        new Thread( null, new Runnable() {
//            @Override
//            public void run() {
//                new Main().run();
//            }
//            }, "LOL", 256L * 1024 * 1024 / 2 ).run();
//        }, "LOL", 2000 * 1024 * 1024 ).run();
    }

    void TLE(){ for(;;); }

    void MLE(){
        int[][] adj = new int[1024*1024][];
        for( int i = 0; i < adj.length; ++i )
            adj[i] = new int[1024*1024];
    }

    void exit( int val ){
        out.flush();
        System.exit(val);
    }
    //////////////////////////////////////////////////////////////////////////////////////////

    long[][][] dp;
    final long inf = Long.MAX_VALUE / 1000,
        mod = 1000000007 ;

    BigInteger fact( int n ){
        return n<=1? ONE : valueOf(n).multiply(fact(n-1));
    }

    long C( int m, int n ){
        if(!( m <= n )) MLE();
        return fact(n).divide( fact(m).multiply(fact(n-m)) ).mod(valueOf(mod)).longValue();
    }

    long powMod( long a, long p ){
        if( p == 0 ) return 1;
        long ans = powMod(a,p/2);
        ans = (ans*ans) % mod;
        if( p%2==1 ) ans = (a*ans) % mod;
        return ans;
    }

    long getDP( int n, int k, int isNeed ){
        if (n <= 0 || k < 0) return 0;

        if( dp[n][k][isNeed] == inf ){
            long ans = 0;

            if( n == 1 ){
                if( k==0 && isNeed == 0 )
                    ans = 1;
                else
                    ans = 0;
            }
            else{
                for( int nl = 1; nl <= n-2; ++nl ){
                for( int kl = 0; kl <= (isNeed==1?k-1:k); ++kl ){
                    long cur = (C(nl,n-1) * n) % mod;
                    if( isNeed==1 ){
                        cur *=(
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 1)%mod +
                            getDP(nl, kl, 1)*getDP(n-1-nl, k-1-kl, 0)%mod +
                            getDP(nl, kl, 0)*getDP(n-1-nl, k-1-kl, 0)%mod
                        ) % mod;
                    }
                    else{
                        cur *=
                            getDP(nl,kl,1)*getDP(n-1-nl,k-kl,1) % mod;
                    }
                    ans = (ans + cur) % mod;
                    if( n==3 ){
                        n = 3;
//                        out.printf( ":: %d/%d   %d/%d  %d\n", nl,n,   kl,k, isNeed );
                    }
                }
                }
                ans = ans * powMod(2,mod-2) % mod;
                if( isNeed == 1 )
                    ans = ( ans + n*getDP(n-1,k-1,0) ) %mod;
                else
                    ans = ( ans + n*getDP(n-1,k  ,1) ) %mod;
            }
            dp[n][k][isNeed] = ans;
        }
        return dp[n][k][isNeed];
    }

    void solve(){
        int n, k;

        n = sc.nextInt();
        k = sc.nextInt();
        dp = new long[n+1][k+1][2];
        for( long[][] a : dp )
            for( long[] b : a )
                fill( b, inf );

        long ans = getDP(n, k, 0) + getDP(n, k, 1);
        ans %= mod;
        ans = ans * powMod( n, mod - 2 ) % mod;
        out.println( ans );
    }

}


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

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

	static class TaskE {
		List<Long> ps;

		public void solve(int testNumber, FastScanner in, PrintWriter out) {
			long x = in.nextLong();
			long y = in.nextLong();
			calcPrimeDivisors(x);
			out.println(f(x, y));
		}

		private void calcPrimeDivisors(long x) {
			ps = new ArrayList<>();
			for (long p = 2; p * p <= x; p++) {
				if (x % p == 0) {
					ps.add(p);
					while (x % p == 0) {
						x /= p;
					}
				}
			}
			if (x > 1) {
				ps.add(x);
			}
		}

		private long f(long a, long b) {
			if (b == 0) {
				return 0;
			}
			long d = gcd(a, b);
			if (d != 1) {
				return f(a / d, b / d);
			}
			long bestB = b - 1;
			for (long p : ps) {
				long nb = b / p * p;
				if (gcd(a, nb) != 1) {
					bestB = Math.max(bestB, nb);
				}
			}
			return b - bestB + f(a, bestB);
		}

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

	}

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

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

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

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

	}
}


import java.util.Arrays;
import java.util.Scanner;

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

	public void run() {
		Scanner sc = new Scanner(System.in);
		long a = sc.nextLong();
		long b = sc.nextLong();
		System.out.println(f(a, b));
	}

	long f(long a, long b) {
		if (a == b)
			return 1;
		if (b == 0) {
			return 0;
		}
		if (isPrime(a)) {
			if (a <= b) {
				return f(a, a) + (b - a);
			} else {
				return b;
			}
		}
		long gcd = gcd(a, b);
		return 1 + f(a / gcd, b / gcd - 1);
		// int c = 1;
		// while (b > 0 && gcd(a, b) == 1) {
		// --b;
		// }
		// if (gcd(a, b) != 1) {
		// long gcd = gcd(a, b);
		// return c + f(a / gcd, b / gcd - 1);
		// } else {
		// return c + f(a, b);
		// }
	}

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

	static boolean isPrime(long n) {
		// 間違える確率4^(-k)=10^(-6)
		if (n == 1 || n % 2 == 0)
			return false;
		long z = n - 1;
		int c2 = 0;
		while (z % 2 == 0) {
			z /= 2;
			++c2;
		}
		outer: for (int k = 0; k < 10; ++k) {
			long a = (int) (Math.random() * 10000) % n;
			if (a == 0)
				continue;
			a = pow(a, z, n);
			if (a == 1 || a == n - 1)
				continue outer;
			for (int i = 0; i < c2 - 1; ++i) {
				a = (a * a) % n;
				if (a == n - 1)
					continue outer;
			}
			return false;
		}
		return true;
	}

	static long pow(long a, long n, long mod) {
		long ret = 1;
		for (; n > 0; n >>= 1, a = (a * a) % mod) {
			if (n % 2 == 1) {
				ret = (ret * a) % mod;
			}
		}
		return ret;
	}

	static void tr(Object... objects) {
		System.out.println(Arrays.deepToString(objects));
	}
}


/*
Keep solving problems.
*/

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

public class CFA {
    BufferedReader br;
    PrintWriter out;
    StringTokenizer st;
    boolean eof;
    private static final long MOD = 1000 * 1000 * 1000 + 7;
    private static final int[] dx = {0, -1, 0, 1};
    private static final int[] dy = {1, 0, -1, 0};
    private static final String yes = "Yes";
    private static final String no = "No";

    long res = 0;
    void solve() throws IOException {
        long x = nextLong();
        long y = nextLong();
        helper(x, y);
        outln(res);
    }

    void helper(long x, long y) {
        if (isPrime(x)) {
            res += y / x + y % x;
            return;
        }

        long g = gcd(x, y);
        helper(x / g, y / g);
    }

    boolean isPrime(long x) {
        for (long i = 2; i * i <= x; i++) {
            if (x % i == 0) {
                return false;
            }
        }

        return true;
    }

    void shuffle(int[] a) {
        int n = a.length;
        for(int i = 0; i < n; i++) {
            int r = i + (int) (Math.random() * (n - i));
            int tmp = a[i];
            a[i] = a[r];
            a[r] = tmp;
        }
    }

    long gcd(long a, long b) {
        while(a != 0 && b != 0) {
            long c = b;
            b = a % b;
            a = c;
        }
        return a + b;
    }

    private void outln(Object o) {
        out.println(o);
    }
    private void out(Object o) {
        out.print(o);
    }
    private void formatPrint(double val) {
        System.out.format("%.9f%n", val);
    }
    public CFA() throws IOException {
        br = new BufferedReader(new InputStreamReader(System.in));
        out = new PrintWriter(System.out);
        solve();
        out.close();
    }
    public static void main(String[] args) throws IOException {
        new CFA();
    }

    public long[] nextLongArr(int n) throws IOException{
        long[] res = new long[n];
        for(int i = 0; i < n; i++)
            res[i] = nextLong();
        return res;
    }
    public int[] nextIntArr(int n) throws IOException {
        int[] res = new int[n];
        for(int i = 0; i < n; i++)
            res[i] = nextInt();
        return res;
    }
    public String nextToken() {
        while (st == null || !st.hasMoreTokens()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception e) {
                eof = true;
                return null;
            }
        }
        return st.nextToken();
    }
    public String nextString() {
        try {
            return br.readLine();
        } catch (IOException e) {
            eof = true;
            return null;
        }
    }
    public int nextInt() throws IOException {
        return Integer.parseInt(nextToken());
    }
    public long nextLong() throws IOException {
        return Long.parseLong(nextToken());
    }
    public double nextDouble() throws IOException {
        return Double.parseDouble(nextToken());
    }
}


import java.util.*;

public class e{
	static long gcd(long a, long b){
		return b == 0? a: gcd(b, a % b);
	}
	// okay
	// i see why i got hacked
	// i only considered the SMALLEST factor of x
	// i should really consider ALL factors of x

	static long f(long x, long y){
		if(y == 0) return 0;
		if(x == 1 || y == 1) return y;
		long gcd = gcd(x,y);
		if(gcd > 1){
			return f(x / gcd, y / gcd);
		}

		// smallest factor of f?
		long diff = Long.MAX_VALUE;
		long fac, temp;
		for(fac = 2, temp = x; fac*fac <= temp; fac++){
			if(temp % fac == 0){
				diff = Math.min(diff, y - (y / fac * fac));
				while(temp % fac == 0){
					temp /= fac;
				}
			}
		}
		if(fac*fac > temp){
			diff = Math.min(diff, y - (y / temp * temp));
		}

		return diff + f(x, y - diff);
	}
	public static void main(String[] args) {
		Scanner in = new Scanner(System.in);
		long X = in.nextLong();
		long Y = in.nextLong();

		System.out.println(f(X,Y));
	}
}