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

/**
 * @author Pavel Mavrin
 */
public class E {

    private static final int MOD = (int) (1e9+7);
    public static final int N = 7;
    public static final int NN = 128;

    private void solve() throws IOException {
        int[] w = new int[N];
        for (int i = 0; i < N; i++) {
            w[i] = nextInt();
        }
        int[] start = new int[2];
        start[1] = 1;
        int[] a = start;
        for (int h = 0; h < N; h++) if (w[h] > 0) {
            int nn = (1 << (h + 1));
            {
                int[] aa = new int[nn];
                for (int i = 0; i < a.length; i++) {
                    aa[i - a.length + nn] = a[i];
                }
                a = aa;
            }
            int[][] q = new int[nn][];
            int[] t = new int[nn];
            for (int i = 0; i < nn; i++) {
                t[i] = 1;
                q[i] = add(t, h + 1);
                t[i] = 0;
            }
            q = pow(q, w[h]);
            int[] aa = new int[nn];
            for (int i = 0; i < nn; i++) {
                for (int j = 0; j < nn; j++) {
                    aa[j] = (int) ((aa[j] + 1l * a[i] * q[i][j]) % MOD);
                }
            }
            a = aa;
        }
        out.println(a[a.length - 1]);
    }

    private int[][] pow(int[][] a, int b) {
        int n = a.length;
        if (b == 0) {
            int[][] res = new int[n][n];
            for (int i = 0; i < n; i++) {
                res[i][i] = 1;
            }
            return res;
        }
        if (b % 2 == 0) {
            int[][] aa = mult(a, a);
            return pow(aa, b / 2);
        } else {
            int[][] aa = pow(a, b - 1);
            return mult(aa, a);
        }
    }

    private int[][] mult(int[][] a, int[][] b) {
        int n = a.length;
        int[][] c = new int[n][n];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) {
                for (int k = 0; k < n; k++) {
                    c[i][k] = (int) ((c[i][k] + 1l * a[i][j] * b[j][k]) % MOD);
                }
            }
        }
        return c;
    }

    private int[] add(int[] a, int n) {
        int nn = (1 << (n + 1));
        int[][] d = new int[n + 1][nn];
        for (int i = 0; i < nn / 2; i++) {
            d[0][(i << 1) + 1] = a[i + a.length - (1 << n)];
        }
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < nn; j++) if (d[i][j] > 0) {
                int q = (j >> i) & 3;
                for (int k = 0; k < 4; k++) {
                    if (q == 3 && k == 3) continue;
                    int jj = (j - (q << i) + (k << i));
                    d[i + 1][jj] += d[i][j];
                    while (d[i + 1][jj] >= MOD) {
                        d[i + 1][jj] -= MOD;
                    }
                }
            }
        }
        int[] res = new int[a.length];
        for (int i = 0; i < (1 << n); i++) {
            res[i + a.length - (1 << n)] = d[n][i + (1 << n)];
        }
        return res;
    }

    BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
    StringTokenizer st;
    PrintWriter out = new PrintWriter(System.out);

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

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

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

    private void run() throws IOException {
        solve();
        out.close();
    }

}


/*
    Author: Anthony Ngene
    Created: 04/10/2020 - 12:56
*/

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

public class F {
// checks: 1. edge cases   2. overflow   3. possible errors (e.g 1/0, arr[out])   4. time/space complexity
    int n;
    int m;
    int[] arr;
    int required;
    HashMap<Integer, TreeSet<Integer>> typeDays;
    void solver() throws IOException {
        n = in.intNext(); m = in.intNext();
        arr = in.nextIntArray(n);
        required = sum(arr);
        typeDays = new HashMap<>();
        for (int i = 0; i < m; i++) {
            int d = in.intNext(), typ = in.intNext();
            if (arr[typ - 1] <= 0) continue;
            if (!typeDays.containsKey(typ)) typeDays.put(typ, new TreeSet<>());
            typeDays.get(typ).add(d);
        }

        int lo = required;
        int hi = 2 * required;
        int valid = hi;
        while (lo <= hi) {
            int mid = (lo + hi) / 2;
            if (isEnough(mid)) {
                valid = mid;
                hi = mid - 1;
            } else
                lo = mid + 1;
        }
        out.println(valid);
    }

    boolean isEnough(int day) {
        int totalCoin = day;
        int req = required;

        int[] ddays = new int[day + 1];
        for (int typ : typeDays.keySet()) {
            Integer lastDay = typeDays.get(typ).floor(day);
            if (lastDay == null) continue;
            ddays[lastDay] += arr[typ - 1];
        }
//        out.println(ddays);
        int removed = 0;
        for (int i = 1; i < day + 1; i++) {
            int coins = i - removed;
            int toRemove = min(coins, ddays[i]);
            removed += toRemove;
            totalCoin -= toRemove;
            req -= toRemove;
        }
//        out.pp(req, totalCoin);
        return req * 2 <= totalCoin;
    }

// Generated Code Below:
private static final FastWriter out = new FastWriter();
private static FastScanner in;
static ArrayList<Integer>[] adj;
private static long e97 = (long)1e9 + 7;
public static void main(String[] args) throws IOException {
    in = new FastScanner();
    new F().solver();
    out.close();
}

static class FastWriter {
    private static final int IO_BUFFERS = 128 * 1024;
    private final StringBuilder out;
    public FastWriter() { out = new StringBuilder(IO_BUFFERS); }
    public FastWriter p(Object object) { out.append(object); return this; }
    public FastWriter p(String format, Object... args) { out.append(String.format(format, args)); return this; }
    public FastWriter pp(Object... args) { for (Object ob : args) { out.append(ob).append(" ");  } out.append("\n"); return this; }
    public FastWriter pp(int[] args) { for (int ob : args) { out.append(ob).append(" ");  } out.append("\n"); return this; }
    public FastWriter pp(long[] args) { for (long ob : args) { out.append(ob).append(" ");  } out.append("\n"); return this; }
    public FastWriter pp(char[] args) { for (char ob : args) { out.append(ob).append(" ");  } out.append("\n"); return this; }
    public void println(long[] arr) { for(long e: arr) out.append(e).append(" "); out.append("\n"); }
    public void println(int[] arr) { for(int e: arr) out.append(e).append(" "); out.append("\n"); }
    public void println(char[] arr) { for(char e: arr) out.append(e).append(" "); out.append("\n"); }
    public void println(double[] arr) { for(double e: arr) out.append(e).append(" "); out.append("\n"); }
    public void println(boolean[] arr) { for(boolean e: arr) out.append(e).append(" "); out.append("\n"); }
    public <T>void println(T[] arr) { for(T e: arr) out.append(e).append(" "); out.append("\n"); }
    public void println(long[][] arr) {  for (long[] row: arr) out.append(Arrays.toString(row)).append("\n"); }
    public void println(int[][] arr) {  for (int[] row: arr) out.append(Arrays.toString(row)).append("\n"); }
    public void println(char[][] arr) {  for (char[] row: arr) out.append(Arrays.toString(row)).append("\n"); }
    public void println(double[][] arr) {  for (double[] row: arr) out.append(Arrays.toString(row)).append("\n"); }
    public <T>void println(T[][] arr) {  for (T[] row: arr) out.append(Arrays.toString(row)).append("\n"); }
    public FastWriter println(Object object) { out.append(object).append("\n"); return this; }
    public void toFile(String fileName) throws IOException {
        BufferedWriter writer = new BufferedWriter(new FileWriter(fileName));
        writer.write(out.toString());
        writer.close();
    }
    public void close() throws IOException { System.out.print(out); }
}
static class FastScanner {
    private InputStream sin = System.in;
    private final byte[] buffer = new byte[1024];
    private int ptr = 0;
    private int buflen = 0;
    public FastScanner(){}
    public FastScanner(String filename) throws FileNotFoundException {
        File file = new File(filename);
        sin = new FileInputStream(file);
    }
    private boolean hasNextByte() {
        if (ptr < buflen) {
            return true;
        }else{
            ptr = 0;
            try {
                buflen = sin.read(buffer);
            } catch (IOException e) {
                e.printStackTrace();
            }
            if (buflen <= 0) {
                return false;
            }
        }
        return true;
    }
    private int readByte() { if (hasNextByte()) return buffer[ptr++]; else return -1;}
    private static boolean isPrintableChar(int c) { return 33 <= c && c <= 126;}
    public boolean hasNext() { while(hasNextByte() && !isPrintableChar(buffer[ptr])) ptr++; return hasNextByte();}
    public String next() {
        if (!hasNext()) throw new NoSuchElementException();
        StringBuilder sb = new StringBuilder();
        int b = readByte();
        while(isPrintableChar(b)) {
            sb.appendCodePoint(b);
            b = readByte();
        }
        return sb.toString();
    }
    public long longNext() {
        if (!hasNext()) throw new NoSuchElementException();
        long n = 0;
        boolean minus = false;
        int b = readByte();
        if (b == '-') {
            minus = true;
            b = readByte();
        }
        if (b < '0' || '9' < b) {
            throw new NumberFormatException();
        }
        while(true){
            if ('0' <= b && b <= '9') {
                n *= 10;
                n += b - '0';
            }else if(b == -1 || !isPrintableChar(b) || b == ':'){
                return minus ? -n : n;
            }else{
                throw new NumberFormatException();
            }
            b = readByte();
        }
    }
    public int intNext() {
        long nl = longNext();
        if (nl < Integer.MIN_VALUE || nl > Integer.MAX_VALUE) throw new NumberFormatException();
        return (int) nl;
    }
    public double doubleNext() { return Double.parseDouble(next());}
    public long[] nextLongArray(final int n){
        final long[] a = new long[n];
        for (int i = 0; i < n; i++)
            a[i] = longNext();
        return a;
    }
    public int[] nextIntArray(final int n){
        final int[] a = new int[n];
        for (int i = 0; i < n; i++)
            a[i] = intNext();
        return a;
    }
    public double[] nextDoubleArray(final int n){
        final double[] a = new double[n];
        for (int i = 0; i < n; i++)
            a[i] = doubleNext();
        return a;
    }
    public ArrayList<Integer>[] getAdj(int n) {
        ArrayList<Integer>[] adj = new ArrayList[n + 1];
        for (int i = 1; i <= n; i++) adj[i] = new ArrayList<>();
        return adj;
    }
    public ArrayList<Integer>[] adjacencyList(int nodes, int edges) throws IOException {
        return adjacencyList(nodes, edges, false);
    }
    public ArrayList<Integer>[] adjacencyList(int nodes, int edges, boolean isDirected) throws IOException {
        adj = getAdj(nodes);
        for (int i = 0; i < edges; i++) {
            int a = intNext(), b = intNext();
            adj[a].add(b);
            if (!isDirected) adj[b].add(a);
        }
        return adj;
    }
}
static class u {
    public static int upperBound(long[] array, long obj) {
        int l = 0, r = array.length - 1;
        while (r - l >= 0) {
            int c = (l + r) / 2;
            if (obj < array[c]) {
                r = c - 1;
            } else {
                l = c + 1;
            }
        }
        return l;
    }
    public static int upperBound(ArrayList<Long> array, long obj) {
        int l = 0, r = array.size() - 1;
        while (r - l >= 0) {
            int c = (l + r) / 2;
            if (obj < array.get(c)) {
                r = c - 1;
            } else {
                l = c + 1;
            }
        }
        return l;
    }
    public static int lowerBound(long[] array, long obj) {
        int l = 0, r = array.length - 1;
        while (r - l >= 0) {
            int c = (l + r) / 2;
            if (obj <= array[c]) {
                r = c - 1;
            } else {
                l = c + 1;
            }
        }
        return l;
    }
    public static int lowerBound(ArrayList<Long> array, long obj) {
        int l = 0, r = array.size() - 1;
        while (r - l >= 0) {
            int c = (l + r) / 2;
            if (obj <= array.get(c)) {
                r = c - 1;
            } else {
                l = c + 1;
            }
        }
        return l;
    }
    static <T> T[][] deepCopy(T[][] matrix) { return Arrays.stream(matrix).map(el -> el.clone()).toArray($ -> matrix.clone()); }
    static int[][] deepCopy(int[][] matrix) { return Arrays.stream(matrix).map(int[]::clone).toArray($ -> matrix.clone()); }
    static long[][] deepCopy(long[][] matrix) { return Arrays.stream(matrix).map(long[]::clone).toArray($ -> matrix.clone()); }
    private static void sort(int[][] arr){ Arrays.sort(arr, Comparator.comparingDouble(o -> o[0])); }
    private static void sort(long[][] arr){ Arrays.sort(arr, Comparator.comparingDouble(o -> o[0])); }
    private static <T>void rSort(T[] arr) { Arrays.sort(arr, Collections.reverseOrder()); }
    private static void customSort(int[][] arr) {
        Arrays.sort(arr, new Comparator<int[]>() {
            public int compare(int[] a, int[] b) {
                if (a[0] == b[0]) return Integer.compare(a[1], b[1]);
                return Integer.compare(a[0], b[0]);
            }
        });
    }
    public static int[] swap(int[] arr, int left, int right) {
        int temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        return arr;
    }
    public static char[] swap(char[] arr, int left, int right) {
        char temp = arr[left];
        arr[left] = arr[right];
        arr[right] = temp;
        return arr;
    }
    public static int[] reverse(int[] arr, int left, int right) {
        while (left < right) {
            int temp = arr[left];
            arr[left++] = arr[right];
            arr[right--] = temp;
        }
        return arr;
    }
    public static boolean findNextPermutation(int[] data) {
        if (data.length <= 1) return false;
        int last = data.length - 2;
        while (last >= 0) {
            if (data[last] < data[last + 1]) break;
            last--;
        }
        if (last < 0) return false;
        int nextGreater = data.length - 1;
        for (int i = data.length - 1; i > last; i--) {
            if (data[i] > data[last]) {
                nextGreater = i;
                break;
            }
        }
        data = swap(data, nextGreater, last);
        data = reverse(data, last + 1, data.length - 1);
        return true;
    }
    public static int biSearch(int[] dt, int target){
        int left=0, right=dt.length-1;
        int mid=-1;
        while(left<=right){
            mid = (right+left)/2;
            if(dt[mid] == target) return mid;
            if(dt[mid] < target) left=mid+1;
            else right=mid-1;
        }
        return -1;
    }
    public static int biSearchMax(long[] dt, long target){
        int left=-1, right=dt.length;
        int mid=-1;

        while((right-left)>1){
            mid = left + (right-left)/2;
            if(dt[mid] <= target) left=mid;
            else right=mid;
        }
        return left;
    }
    public static int biSearchMaxAL(ArrayList<Integer> dt, long target){
        int left=-1, right=dt.size();
        int mid=-1;

        while((right-left)>1){
            mid = left + (right-left)/2;
            if(dt.get(mid) <= target) left=mid;
            else right=mid;
        }
        return left;
    }
    private static <T>void fill(T[][] ob, T res){for(int i=0;i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(boolean[][] ob,boolean res){for(int i=0;i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(int[][] ob, int res){      for(int i=0; i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(long[][] ob, long res){    for(int i=0; i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(char[][] ob, char res){    for(int i=0; i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(double[][] ob, double res){for(int i=0; i<ob.length; i++){ for(int j=0; j<ob[0].length; j++){  ob[i][j] = res; }}}
    private static void fill(int[][][] ob,int res){for(int i=0;i<ob.length;i++){for(int j=0;j<ob[0].length;j++){for(int k=0;k<ob[0][0].length;k++){ob[i][j][k]=res;}}}}
    private static void fill(long[][][] ob,long res){for(int i=0;i<ob.length;i++){for(int j=0;j<ob[0].length;j++){for(int k=0;k<ob[0][0].length;k++){ob[i][j][k]=res;}}}}
    private static <T>void fill(T[][][] ob,T res){for(int i=0;i<ob.length;i++){for(int j=0;j<ob[0].length;j++){for(int k=0;k<ob[0][0].length;k++){ob[i][j][k]=res;}}}}
    private static void fill_parent(int[] ob){ for(int i=0; i<ob.length; i++) ob[i]=i; }
    private static boolean same3(long a, long b, long c){
        if(a!=b) return false;
        if(b!=c) return false;
        if(c!=a) return false;
        return true;
    }
    private static boolean dif3(long a, long b, long c){
        if(a==b) return false;
        if(b==c) return false;
        if(c==a) return false;
        return true;
    }
    private static double hypotenuse(double a, double b){
        return Math.sqrt(a*a+b*b);
    }
    private static long factorial(int n) {
        long ans=1;
        for(long i=n; i>0; i--){ ans*=i; }
        return ans;
    }
    private static long facMod(int n, long mod) {
        long ans=1;
        for(long i=n; i>0; i--) ans = (ans * i) % mod;
        return ans;
    }
    private static long lcm(long m, long n){
        long ans = m/gcd(m,n);
        ans *= n;
        return ans;
    }
    private static long gcd(long m, long n) {
        if(m < n) return gcd(n, m);
        if(n == 0) return m;
        return gcd(n, m % n);
    }
    private static boolean isPrime(long a){
        if(a==1) return false;
        for(int i=2; i<=Math.sqrt(a); i++){  if(a%i == 0) return false;  }
        return true;
    }
    static long modInverse(long a, long mod) {
    /* Fermat's little theorem: a^(MOD-1) => 1
    Therefore (divide both sides by a): a^(MOD-2) => a^(-1) */
        return binpowMod(a, mod - 2, mod);
    }
    static long binpowMod(long a, long b, long mod) {
        long res = 1;
        while (b > 0) {
            if (b % 2 == 1) res = (res * a) % mod;
            a = (a * a) % mod;
            b /= 2;
        }
        return res;
    }
    private static int getDigit2(long num){
        long cf = 1;    int d=0;
        while(num >= cf){   d++;    cf = 1<<d;  }
        return d;
    }
    private static int getDigit10(long num){
        long cf = 1;    int d=0;
        while(num >= cf){   d++;    cf*=10;     }
        return d;
    }
    private static boolean isInArea(int y, int x, int h, int w){
        if(y<0) return false;
        if(x<0) return false;
        if(y>=h) return false;
        if(x>=w) return false;
        return true;
    }
    private static ArrayList<Integer> generatePrimes(int n) {
        int[] lp = new int[n + 1];
        ArrayList<Integer> pr = new ArrayList<>();
        for (int i = 2; i <= n; ++i) {
            if (lp[i] == 0) {
                lp[i] = i;
                pr.add(i);
            }
            for (int j = 0; j < pr.size() && pr.get(j) <= lp[i] && i * pr.get(j) <= n; ++j) {
                lp[i * pr.get(j)] = pr.get(j);
            }
        }
        return pr;
    }
    static long nPrMod(int n, int r, long MOD) {
        long res = 1;
        for (int i = (n - r + 1); i <= n; i++) {
            res = (res * i) % MOD;
        }
        return res;
    }
    static long nCr(int n, int r) {
        if (r > (n - r))
            r = n - r;
        long ans = 1;
        for (int i = 1; i <= r; i++) {
            ans *= n;
            ans /= i;
            n--;
        }
        return ans;
    }
    static long nCrMod(int n, int r, long MOD) {
        long rFactorial = nPrMod(r, r, MOD);
        long first = nPrMod(n, r, MOD);
        long second = binpowMod(rFactorial, MOD-2, MOD);
        return  (first * second) % MOD;
    }
    static void printBitRepr(int n) {
        StringBuilder res = new StringBuilder();
        for (int i = 0; i < 32; i++) {
            int mask = (1 << i);
            res.append((mask & n) == 0 ? "0" : "1");
        }
        out.println(res);
    }
    static String bitString(int n) {return Integer.toBinaryString(n);}
    static int setKthBitToOne(int n, int k) { return (n | (1 << k)); } // zero indexed
    static int setKthBitToZero(int n, int k) { return (n & ~(1 << k)); }
    static int invertKthBit(int n, int k) { return (n ^ (1 << k)); }
    static boolean isPowerOfTwo(int n) { return (n & (n - 1)) == 0; }
    static HashMap<Character, Integer> counts(String word) {
        HashMap<Character, Integer> counts = new HashMap<>();
        for (int i = 0; i < word.length(); i++) counts.merge(word.charAt(i), 1, Integer::sum);
        return counts;
    }
    static HashMap<Integer, Integer> counts(int[] arr) {
        HashMap<Integer, Integer> counts = new HashMap<>();
        for (int value : arr) counts.merge(value, 1, Integer::sum);
        return counts;
    }
    static HashMap<Long, Integer> counts(long[] arr) {
        HashMap<Long, Integer> counts = new HashMap<>();
        for (long l : arr) counts.merge(l, 1, Integer::sum);
        return counts;
    }
    static HashMap<Character, Integer> counts(char[] arr) {
        HashMap<Character, Integer> counts = new HashMap<>();
        for (char c : arr) counts.merge(c, 1, Integer::sum);
        return counts;
    }
    static long hash(int x, int y) {
        return x* 1_000_000_000L +y;
    }
    static final Random random = new Random();
    static void sort(int[] a) {
        int n = a.length;// shuffle, then sort
        for (int i = 0; i < n; i++) {
            int oi = random.nextInt(n), temp = a[oi];
            a[oi] = a[i];
            a[i] = temp;
        }
        Arrays.sort(a);
    }
    static void sort(long[] arr) {
        shuffleArray(arr);
        Arrays.sort(arr);
    }
    static void shuffleArray(long[] arr) {
        int n = arr.length;
        for(int i=0; i<n; ++i){
            long tmp = arr[i];
            int randomPos = i + random.nextInt(n-i);
            arr[i] = arr[randomPos];
            arr[randomPos] = tmp;
        }
    }
}
static class Tuple implements Comparable<Tuple> {
    int a;
    int b;
    int c;
    public Tuple(int a, int b) {
        this.a = a;
        this.b = b;
        this.c = 0;
    }
    public Tuple(int a, int b, int c) {
        this.a = a;
        this.b = b;
        this.c = c;
    }
    public int getA() { return a; }
    public int getB() { return b; }
    public int getC() { return c; }
    public int compareTo(Tuple other) {
        if (this.a == other.a) {
            if (this.b == other.b) return Long.compare(this.c, other.c);
            return Long.compare(this.b, other.b);
        }
        return Long.compare(this.a, other.a);
    }
    @Override
    public int hashCode() { return Arrays.deepHashCode(new Integer[]{a, b, c}); }
    @Override
    public boolean equals(Object o) {
        if (!(o instanceof Tuple)) return false;
        Tuple pairo = (Tuple) o;
        return (this.a == pairo.a && this.b == pairo.b && this.c == pairo.c);
    }
    @Override
    public String toString() { return String.format("(%d %d %d)  ", this.a, this.b, this.c); }
}
private static int abs(int a){  return (a>=0) ? a: -a;  }
private static int min(int... ins){ int min = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] < min) min = ins[i]; } return min; }
private static int max(int... ins){ int max = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] > max) max = ins[i]; } return max; }
private static int sum(int... ins){ int total = 0; for (int v : ins) { total += v; } return total; }
private static long abs(long a){    return (a>=0) ? a: -a;  }
private static long min(long... ins){ long min = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] < min) min = ins[i]; } return min; }
private static long max(long... ins){ long max = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] > max) max = ins[i]; } return max; }
private static long sum(long... ins){ long total = 0; for (long v : ins) { total += v; } return total; }
private static double abs(double a){    return (a>=0) ? a: -a;  }
private static double min(double... ins){ double min = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] < min) min = ins[i]; } return min; }
private static double max(double... ins){ double max = ins[0]; for(int i=1; i<ins.length; i++){ if(ins[i] > max) max = ins[i]; } return max; }
private static double sum(double... ins){ double total = 0; for (double v : ins) { total += v; } return total; }

}


import java.io.*;
import java.math.BigInteger;
public class flags{
public static int mod = 1000000007,modi = (mod+1)>>1;
public static BigInteger modB = new BigInteger("1000000007");
public static BigInteger modiB = new BigInteger("500000004");
public static long id[][] ={{1,0,0,0,0,0,0},{0,1,0,0,0,0,0},{0,0,1,0,0,0,0},{0,0,0,1,0,0,0},{0,0,0,0,1,0,0},{0,0,0,0,0,1,0},{0,0,0,0,0,0,1}};
public static long a[][] = {{1,0,0,0,0,0,0},{1,0,0,0,0,0,0},{1,1,0,0,1,1,0},{1,1,0,0,1,0,1},{1,0,1,1,0,0,0},{0,0,1,0,0,0,0},{0,0,0,1,0,0,0}};//adyacencia aut
public static void main(String args[]) throws IOException{
BufferedReader lector= new BufferedReader(new InputStreamReader(System.in));
String tmp = lector.readLine();
int n2 = Integer.parseInt(tmp.substring(0,tmp.indexOf(" ")))-1;
int n1 = Integer.parseInt(tmp.substring(tmp.indexOf(" ")+1));
BigInteger un = f(a,n1);
BigInteger dos = f(a,n1/2+(n1&1));
un = ((un.subtract(dos).multiply(modiB)).add(dos)).mod(modB);
BigInteger un1 = f(a,n2);
BigInteger dos1 = f(a,n2/2+(n2&1));
un1 = ((un1.subtract(dos1).multiply(modiB)).add(dos1)).mod(modB);
BigInteger joder = un.subtract(un1);
while(joder.compareTo(BigInteger.ZERO)<0)joder = joder.add(modB);
System.out.println(joder);
}
public static BigInteger f(long a[][],int n){
long p[][] = exp(a,n);
BigInteger res = BigInteger.ZERO;
int ri[] = {0,1,1,1,1,1,1};//terminales de cada nodo
for(int nn = 0;nn<p.length;nn++)res=(res.add(new BigInteger(""+p[nn][0]).multiply(new BigInteger(""+ri[nn])))).mod(modB);
return res.mod(modB);
/*
//if((n&1)==1){
p = exp(a,n/2+1);
int r[] = {0,1,1,1,1,1,1};
//int r[] = {4,2,2,2,2,1,1};//terminales de cada nodo
BigInteger res2 = BigInteger.ZERO;
for(int nn = 0;nn<p.length;nn++)res2=(res2.add(new BigInteger(""+p[nn][0]).multiply(new BigInteger(""+r[nn])))).mod(modB);
return (((res.subtract(res2)).multiply(modiB)).mod(modB).add(res2)).mod(modB);
//}
//return (res.multiply(modiB)).mod(modB);
*/
}
public static long[][] mul(long[][] a,long[][] b){
long res[][] = new long[a.length][b[0].length];
for(int n = 0;n<res.length;n++)
for(int m = 0;m<res[n].length;m++){
long tal = 0;
for(int x = 0;x<res[0].length;x++)
tal = (tal+a[n][x]*b[x][m])%mod;
res[n][m]=tal;
}
return res;
}
public static long[][] exp(long[][] a,int b){
if(b==0)
return id;
if(b==1)return a;
if((b&1)==0)
return exp(mul(a,a),b/2);
return mul(exp(mul(a,a),b/2),a);
}
}


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

public final class Main {

    static PrintWriter out = new PrintWriter(System.out);
    static FastReader in = new FastReader();
    static Pair[] moves = new Pair[]{new Pair(-1, 0), new Pair(0, 1), new Pair(1, 0), new Pair(0, -1)};
    static int mod = (int) (1e9 + 7);
    static int mod2 = 998244353;

    public static void main(String[] args) {
        int tt = 1;
        while (tt-- > 0) {
            solve();
        }
        out.flush();
    }

    public static void solve() {
        int n = i();
        int x = i();
        if (n > x) {
            out.println(pow(x, n, mod2));
        } else {
            initializeFactorial(n, mod2);
            long[][] dp = new long[n + 1][x + 1];
            long ans = pow(x, n, mod2);
            ans -= dfs(dp, n, x);
            if (ans < 0) {
                ans += mod2;
            }
            out.println(ans);
        }

    }

    private static long dfs(long[][] dp, int i, int j) {
        if (dp[i][j] > 0) {
            return dp[i][j];
        }

        long x = 0L;
        if (i == 1) {
            x = j;
        } else if (j == 1) {
            x = 0;
        } else if (i == 2) {
            x = pow(j, 2, mod2) - j;
            if (x < 0) {
                x += mod2;
            }
        } else if (i > j) {
            x = 0;
        } else if (i == j) {
            x = i * pow(i - 1, i - 1, mod2) % mod2;
        } else {
            for (int k = 1; k <= i; k++) {
                long r = pow(i - 1, i - k, mod2);
                r *= binomialCoefficient(i, k, mod2);
                r %= mod2;
                x += (dfs(dp, k, j - i + 1) * r) % mod2;
                x %= mod2;
            }
        }

        dp[i][j] = x;
        return x;
    }

    static long[] fac;
    static long[] inv;

    static void initializeFactorial(int n, int mod) {
        fac = new long[n + 1];
        inv = new long[n + 1];
        long[] v = new long[fac.length];
        fac[0] = inv[0] = 1;
        for (int i = 1; i < fac.length; i++) {
            v[i] = i == 1 ? 1 : v[i - mod % i] * (mod / i + 1);
            v[i] %= mod;
            fac[i] = fac[i - 1] * i;
            fac[i] %= mod;
            inv[i] = inv[i - 1] * v[i];
            inv[i] %= mod;
        }
    }

    static int binomialCoefficient(int n, int k, int m) {
        long res = fac[n] * inv[k];
        res %= m;
        res *= inv[n - k];
        return (int) (res % m);
    }

    static long[] pre(int[] a) {
        long[] pre = new long[a.length + 1];
        pre[0] = 0;
        for (int i = 0; i < a.length; i++) {
            pre[i + 1] = pre[i] + a[i];
        }
        return pre;
    }

    static void print(char A[]) {
        for (char c : A) {
            out.print(c);
        }
        out.println();
    }

    static void print(boolean A[]) {
        for (boolean c : A) {
            out.print(c + " ");
        }
        out.println();
    }

    static void print(int A[]) {
        for (int c : A) {
            out.print(c + " ");
        }
        out.println();
    }

    static void print(long A[]) {
        for (long i : A) {
            out.print(i + " ");
        }
        out.println();
    }

    static void print(List<Integer> A) {
        for (int a : A) {
            out.print(a + " ");
        }
    }

    static int i() {
        return in.nextInt();
    }

    static long l() {
        return in.nextLong();
    }

    static double d() {
        return in.nextDouble();
    }

    static String s() {
        return in.nextLine();
    }

    static int[][] inputWithIdx(int N) {
        int A[][] = new int[N][2];
        for (int i = 0; i < N; i++) {
            A[i] = new int[]{i, in.nextInt()};
        }
        return A;
    }

    static int[] input(int N) {
        int A[] = new int[N];
        for (int i = 0; i < N; i++) {
            A[i] = in.nextInt();
        }
        return A;
    }

    static long[] inputLong(int N) {
        long A[] = new long[N];
        for (int i = 0; i < A.length; i++) {
            A[i] = in.nextLong();
        }
        return A;
    }

    static int GCD(int a, int b) {
        if (b == 0) {
            return a;
        } else {
            return GCD(b, a % b);
        }
    }

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

    static long LCM(int a, int b) {
        return (long) a / GCD(a, b) * b;
    }

    static long LCM(long a, long b) {
        return a / GCD(a, b) * b;
    }

    static void shuffleAndSort(int[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int rand = (int) (Math.random() * arr.length);
            int temp = arr[rand];
            arr[rand] = arr[i];
            arr[i] = temp;
        }
        Arrays.sort(arr);
    }

    static void shuffleAndSort(int[][] arr, Comparator<? super int[]> comparator) {
        for (int i = 0; i < arr.length; i++) {
            int rand = (int) (Math.random() * arr.length);
            int[] temp = arr[rand];
            arr[rand] = arr[i];
            arr[i] = temp;
        }
        Arrays.sort(arr, comparator);
    }

    static void shuffleAndSort(long[] arr) {
        for (int i = 0; i < arr.length; i++) {
            int rand = (int) (Math.random() * arr.length);
            long temp = arr[rand];
            arr[rand] = arr[i];
            arr[i] = temp;
        }
        Arrays.sort(arr);
    }

    static boolean isPerfectSquare(double number) {
        double sqrt = Math.sqrt(number);
        return ((sqrt - Math.floor(sqrt)) == 0);
    }

    static void swap(int A[], int a, int b) {
        int t = A[a];
        A[a] = A[b];
        A[b] = t;
    }

    static long pow(long a, long b, int mod) {
        long pow = 1;
        long x = a;
        while (b != 0) {
            if ((b & 1) != 0) {
                pow = (pow * x) % mod;
            }
            x = (x * x) % mod;
            b /= 2;
        }
        return pow;
    }

    static long pow(long a, long b) {
        long pow = 1;
        long x = a;
        while (b != 0) {
            if ((b & 1) != 0) {
                pow *= x;
            }
            x = x * x;
            b /= 2;
        }
        return pow;
    }

    static long modInverse(long x, int mod) {
        return pow(x, mod - 2, mod);
    }

    static boolean isPrime(long N) {
        if (N <= 1) {
            return false;
        }
        if (N <= 3) {
            return true;
        }
        if (N % 2 == 0 || N % 3 == 0) {
            return false;
        }
        for (int i = 5; i * i <= N; i = i + 6) {
            if (N % i == 0 || N % (i + 2) == 0) {
                return false;
            }
        }
        return true;
    }

    public static String reverse(String str) {
        if (str == null) {
            return null;
        }
        return new StringBuilder(str).reverse().toString();
    }

    public static String repeat(char ch, int repeat) {
        if (repeat <= 0) {
            return "";
        }
        final char[] buf = new char[repeat];
        for (int i = repeat - 1; i >= 0; i--) {
            buf[i] = ch;
        }
        return new String(buf);
    }

    public static int[] manacher(String s) {
        char[] chars = s.toCharArray();
        int n = s.length();
        int[] d1 = new int[n];
        for (int i = 0, l = 0, r = -1; i < n; i++) {
            int k = (i > r) ? 1 : Math.min(d1[l + r - i], r - i + 1);
            while (0 <= i - k && i + k < n && chars[i - k] == chars[i + k]) {
                k++;
            }
            d1[i] = k--;
            if (i + k > r) {
                l = i - k;
                r = i + k;
            }
        }
        return d1;
    }

    public static int[] kmp(String s) {
        int n = s.length();
        int[] res = new int[n];
        for (int i = 1; i < n; ++i) {
            int j = res[i - 1];
            while (j > 0 && s.charAt(i) != s.charAt(j)) {
                j = res[j - 1];
            }
            if (s.charAt(i) == s.charAt(j)) {
                ++j;
            }
            res[i] = j;
        }
        return res;
    }
}

class Pair {

    int i, j;

    Pair(int i, int j) {
        this.i = i;
        this.j = j;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        Pair pair = (Pair) o;
        return i == pair.i && j == pair.j;
    }

    @Override
    public int hashCode() {
        return Objects.hash(i, j);
    }
}

class FastReader {

    BufferedReader br;
    StringTokenizer st;

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

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

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

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

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

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

class Node {

    int data, open, close;

    Node() {
        this(0, 0, 0);
    }

    Node(int data, int open, int close) {
        this.data = data;
        this.open = open;
        this.close = close;
    }
}

class ST {

    int n;
    Node[] st;

    ST(int n) {
        this.n = n;
        st = new Node[4 * Integer.highestOneBit(n)];
    }

    void build(Node[] nodes) {
        build(0, 0, n - 1, nodes);
    }

    private void build(int id, int l, int r, Node[] nodes) {
        if (l == r) {
            st[id] = nodes[l];
            return;
        }
        int mid = (l + r) >> 1;
        build((id << 1) + 1, l, mid, nodes);
        build((id << 1) + 2, mid + 1, r, nodes);
        st[id] = comb(st[(id << 1) + 1], st[(id << 1) + 2]);
    }

    void update(int i, Node node) {
        update(0, 0, n - 1, i, node);
    }

    private void update(int id, int l, int r, int i, Node node) {
        if (i < l || r < i) {
            return;
        }
        if (l == r) {
            st[id] = node;
            return;
        }
        int mid = (l + r) >> 1;
        update((id << 1) + 1, l, mid, i, node);
        update((id << 1) + 2, mid + 1, r, i, node);
        st[id] = comb(st[(id << 1) + 1], st[(id << 1) + 2]);
    }

    Node get(int x, int y) {
        return get(0, 0, n - 1, x, y);
    }

    private Node get(int id, int l, int r, int x, int y) {
        if (x > r || y < l) {
            return new Node();
        }
        if (x <= l && r <= y) {
            return st[id];
        }
        int mid = (l + r) >> 1;
        return comb(get((id << 1) + 1, l, mid, x, y), get((id << 1) + 2, mid + 1, r, x, y));
    }

    Node comb(Node a, Node b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        int min = Math.min(a.open, b.close);
        return new Node(a.data + b.data + min * 2, a.open + b.open - min, a.close + b.close - min);
    }
}


//import java.awt.Dimension;
import java.awt.Point;
import java.io.*;
import static java.lang.Math.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import static java.math.BigInteger.*;
import java.util.*;
import static java.util.Arrays.*;
//import java.math.BigInteger;
//import static java.lang.Character.*;
//import static java.lang.Math.*;
//import static java.math.BigInteger.*;

//import static java.util.Arrays.*;

//import java.awt.Point; // interger !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
//import java.awt.Polygon;
//import java.awt.Rectangle;
//import java.awt.geom.AffineTransform;
//import java.awt.geom.Line2D;
//import java.awt.geom.Point2D;
//import javafx.scene.shape.Line;
//import javafx.scene.transform.Rotate;

//<editor-fold defaultstate="collapsed" desc="Main">
public class Main implements Runnable{

    // https://netbeans.org/kb/73/java/editor-codereference_ru.html#display

    static boolean oj;

    @Override
    public void run(){
        try {
            Locale.setDefault(Locale.US);
        } catch (Exception e) {
        }
        oj = true;
        try {
            oj = System.getProperty("MYLOCAL") == null;
        } catch (Exception e) {
        }
//
        if (oj) {
            sc = new FastScanner(new InputStreamReader(System.in));
            out = new PrintWriter(new OutputStreamWriter(System.out));
        } else {
            try {
                sc = new FastScanner(new FileReader("input.txt"));
                out = new PrintWriter(new FileWriter("output.txt"));
            } catch (IOException e) {
                MLE();
            }
        }
        Solver s = new Solver();
        s.sc = sc;
        s.out = out;

        s.solve();
        if (!oj) {
            err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
            err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        }
        out.flush();
    }

    private void show(int[] arr) {
        for (int v : arr) {
            err.print(" " + v);
        }
        err.println();
    }

    public static void exit() {
        err.println("Time: " + (System.currentTimeMillis() - timeBegin) / 1e3);
        err.printf("Mem: %d\n", (Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory()) >> 20);
        out.flush();
        out.close();
        System.exit(0);
    }

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

    public static void main(String[] args) throws FileNotFoundException {
        //new Main().run();
        new Thread(null, new Main(), "myThread", 100 * 1024 * 1024).start();
    }

    static long timeBegin = System.currentTimeMillis();
    static FastScanner sc;
    static PrintWriter out;
    static PrintStream err = System.err;
}
    //</editor-fold>

//<editor-fold defaultstate="collapsed" desc="FastScanner">
class FastScanner {

    BufferedReader br;
    StringTokenizer st;

    FastScanner(InputStreamReader reader) {
        br = new BufferedReader(reader);
        st = new StringTokenizer("");
    }

    String next() {
        while (!st.hasMoreElements()) {
            try {
                st = new StringTokenizer(br.readLine());
            } catch (Exception ex) {
                return null;
            }
        }
        return st.nextToken();
    }

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

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

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

    String nextLine() {
        try {
            return br.readLine();
        } catch (IOException ex) {
            return null;
        }
    }
}
//</editor-fold>

class Solver {

    void aser(boolean OK) {
        if (!OK) {
            Main.MLE();
        }
    }

    FastScanner sc;
    PrintWriter out;
    static PrintStream err = System.err;

    long[] getAllDiv(long A){
        TreeSet<Long> arr = new TreeSet<>();
        for( long d = 1; d*d <= A; ++d ){
            if( A % d == 0 ) {
                arr.add(d);
                arr.add(A/d);
            }
        }
        int pos = 0;
        long[] a = new long[arr.size()];
        for (long x : arr) a[pos++] = x;
        return a;
    }

    long myPow(long p, int alfa){
        long ans = 1;
        for (int i = 0; i < alfa; i++) {
            ans *= p;
        }
        return ans;
    }

    void solve(){
        final long A = sc.nextLong();
        long[] divA = getAllDiv(A);
        TreeMap<Long,TreeSet<Integer>> P = new TreeMap<>();
        for (long div : divA) {
            --div;
            for (int alfa = 1; alfa <= 60; alfa++) {
                long p = (long)( pow( div, 1.0 / alfa ) + 0.5 );
                if( 2<=p && myPow(p,alfa)==div &&
                        valueOf(p).isProbablePrime(Integer.MAX_VALUE) ){
                    if( !P.containsKey(p) )
                        P.put(p, new TreeSet<>());
                    P.get(p).add(alfa);
                    break;
                }
            }
        }

        long[] dp0, dp;
        dp0 = new long[divA.length];
        dp0[0] = 1;
        for( long p : P.keySet() ){
            dp = dp0.clone();
            for( int alfa : P.get(p) ){
                long val = myPow(p, alfa) + 1;
                for( int ID = 0; ID < divA.length; ++ID){
                    long div = divA[ID];
                    if( 1e12 + 5 <= 1.0 * div * val ) break;
                    long toDiv = div * val;
                    int toID = binarySearch(divA, toDiv);
                    if( 0 <= toID ) dp[toID] += dp0[ID];
                }
            }
            //
            dp0 = dp;
        }
        out.println(dp0[divA.length - 1]);
    }

}


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

public class cf306c {
  static long mod = 1_000_000_009;
  public static void main(String[] args) {
    int MAX = 4020;
    long[] fact = new long[MAX];
    fact[0] = 1;
    for(int i=1; i<MAX; i++)
      fact[i] = (fact[i-1]*i)%mod;
    long[][] choose = new long[MAX][MAX];
    for(int i=0; i<MAX; i++) {
      choose[i][0] = 1;
      for(int j=1; j<=i; j++)
        choose[i][j] = (choose[i-1][j-1] + choose[i-1][j])%mod;
    }

    FastIO in = new FastIO(), out = in;
    int n = in.nextInt();
    int w = in.nextInt();
    int b = in.nextInt();

    long ans = 0;
    for(int bad = 1; bad <= Math.min(bad, n-2); bad++) {
      if(bad > b || (n-bad) > w) continue;
      long tmp = (fact[b]*choose[b-1][bad-1])%mod;
      tmp = (tmp * fact[w])%mod;
      tmp = (tmp * choose[w-1][n-bad-1])%mod;
      tmp = (tmp * (n-bad-1)) % mod;
      ans = (ans+tmp)%mod;
    }
    out.println(ans);
    out.close();
  }
  static class FastIO extends PrintWriter {
    BufferedReader br;
    StringTokenizer st;

    public FastIO() {
      this(System.in, System.out);
    }

    public FastIO(InputStream in, OutputStream out) {
      super(new BufferedWriter(new OutputStreamWriter(out)));
      br = new BufferedReader(new InputStreamReader(in));
      scanLine();
    }

    public void scanLine() {
      try {
        st = new StringTokenizer(br.readLine().trim());
      } catch (Exception e) {
        throw new RuntimeException(e.getMessage());
      }
    }

    public int numTokens() {
      if (!st.hasMoreTokens()) {
        scanLine();
        return numTokens();
      }
      return st.countTokens();
    }

    public String next() {
      if (!st.hasMoreTokens()) {
        scanLine();
        return next();
      }
      return st.nextToken();
    }

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

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

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


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

public class CF273E {

    final static long mod = 1000000007;

    public static void solve(Input in, PrintWriter out) throws IOException {
        int n = in.nextInt();
        int p = in.nextInt();
        ArrayList<Long> starts = new ArrayList<Long>();
        ArrayList<Integer> gs = new ArrayList<Integer>();
        starts.add(0L);
        gs.add(0);
        starts.add(3L);
        gs.add(1);
        long u = 3, v = 1;
        for (int j1 = 0, j2 = 0; u < p; ) {
            while (starts.get(j1 + 1) <= u / 3) {
                ++j1;
            }
            while (starts.get(j2 + 1) <= u - u / 3) {
                ++j2;
            }
            long next1 = starts.get(j1 + 1) * 3;
            if (next1 / 3 < starts.get(j1 + 1) || (next1 - 1) / 3 >= starts.get(j1 + 1)) {
                throw new AssertionError();
            }
            long next2 = (starts.get(j2 + 1) * 3) / 2;
            while (next2 - next2 / 3 < starts.get(j1 + 1)) {
                next2++;
            }
            while (next2 - 1 - (next2 - 1) / 3 >= starts.get(j2 + 1)) {
                next2--;
            }
            if (next2 - next2 / 3 < starts.get(j2 + 1) || next2 - 1 - (next2 - 1) / 3 >= starts.get(j2 + 1)) {
                throw new AssertionError();
            }
            long next = Math.min(next1, next2);
            int val = mutex(gs.get(next >= next1 ? j1 + 1 : j1), gs.get(next >= next2 ? j2 + 1 : j2));
            if (val != v) {
                starts.add(next);
                gs.add(val);
            }
            u = next;
            v = val;
        }
//        System.err.println(starts.size());
        long[] c = new long[3];
        for (int i = 0; i < starts.size(); ++i) {
            long from = starts.get(i);
            long to = i == starts.size() - 1 ? p - 1 : starts.get(i + 1) - 1;
            if (to >= p) {
                to = p - 1;
            }
            if (from > to) {
                continue;
            }
//            System.err.println(from + " " + to + " " + gs.get(i));
//            System.err.println((to - from + 1) * p);
//            System.err.println(to * (to + 1) / 2);
//            System.err.println((from - 1) * (from) / 2);
            c[gs.get(i)] = (c[gs.get(i)] + (to - from + 1) * p) % mod;
            c[gs.get(i)] = (c[gs.get(i)] + mod - (to * (to + 1) / 2 % mod)) % mod;
            c[gs.get(i)] = (c[gs.get(i)] + (from - 1) * (from) / 2) % mod;
        }
        c[0] = (c[0] + mod - p) % mod;
//        for (int i = 1; i < p; ++i) {
//            c[g[i]] = (c[g[i]] + p - i) % mod;
//        }
        long[] d = new long[4];
        d[0] = 1;
        for (int it = 0; it < n; ++it) {
            long[] dd = new long[4];
            for (int i = 0; i < 4; ++i) {
                for (int j = 0; j < 3; ++j) {
                    dd[i ^ j] = (dd[i ^ j] + d[i] * c[j]) % mod;
                }
            }
            d = dd;
        }
        long ans = (d[1] + d[2] + d[3]) % mod;
        out.println(ans);
    }

    private static int mutex(int a, int b) {
        if (a != 0 && b != 0) return 0;
        if (a != 1 && b != 1) return 1;
        return 2;
    }

    public static void main(String[] args) throws IOException {
        PrintWriter out = new PrintWriter(System.out);
        solve(new Input(new BufferedReader(new InputStreamReader(System.in))), out);
        out.close();
    }

    static class Input {
        BufferedReader in;
        StringTokenizer st;

        public Input(BufferedReader in) {
            this.in = in;
            eat("");
        }

        public Input(String s) {
            this.in = new BufferedReader(new StringReader(s));
        }

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

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

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

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

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


// practice with rainboy
import java.io.*;
import java.util.*;

public class CF915G extends PrintWriter {
	CF915G() { super(System.out, true); }
	Scanner sc = new Scanner(System.in);
	public static void main(String[] $) {
		CF915G o = new CF915G(); o.main(); o.flush();
	}

	static final int MD = 1000000007;
	long power(int a, int k) {
		if (k == 0)
			return 1;
		long p = power(a, k >> 1);
		p = p * p % MD;
		if ((k & 1) == 1)
			p = p * a % MD;
		return p;
	}
	void main() {
		int n = sc.nextInt();
		int k = sc.nextInt();
		int[] cc = new int[k + 1];
		for (int a = 2; a <= k; a++) {
			if (cc[a] != 0)
				continue;
			for (int b = a; b <= k; b += a)
				cc[b]++;
		}
		for (int a = 2, a2; (a2 = a * a) <= k; a++)
			for (int b = a2; b <= k; b += a2)
				cc[b] = 0;
		int[] pp = new int[k + 1];
		for (int i = 1; i <= k; i++)
			pp[i] = (int) power(i, n);
		int[] dd = new int[k + 1];
		for (int a = 2; a <= k; a++) {
			if (cc[a] == 0)
				continue;
			for (int i = 1; i * a <= k; i++) {
				int l = i * a, r = (i + 1) * a;
				int p = cc[a] % 2 == 0 ? pp[i] : -pp[i];
				dd[l] = (dd[l] + p) % MD;
				if (r <= k)
					dd[r] = (dd[r] - p) % MD;
			}
		}
		int ans = 0;
		for (int i = 1; i <= k; i++) {
			dd[i] = (dd[i] + dd[i - 1]) % MD;
			int x = (pp[i] + dd[i]) % MD;
			if (x < 0)
				x += MD;
			ans = (ans + (x ^ i)) % MD;
		}
		println(ans);
	}
}


import java.util.*;
public class NewYearAndBinaryTreePaths
{
	public static long k;
	public static long[][][] memo;
	public static int max;
	public static int min;

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

		long s = in.nextLong();

		memo = new long[49][101][201];

		long result = 0;
		for(int x = 0; x <= 50; x++)
		{
			for(int y = 0; y <= 50; y++)
			{
				long mult = (1L << (x + 1)) + (1L << (y + 1)) - 3;
				long lca = s / mult;

				k = s - (lca * mult) - ((1L << y) - 1);

				if(lca > 0 && k >= 0)
				{
					if(Math.max(x, y) <= 1)
					{
						if(k == 0)
						{
							result++;
						}
					}
					else
					{
						max = Math.max(x, y) - 1;
						min = Math.min(x, y) - 1;
						for(long[][] a : memo)
						{
							for(long[] b : a)
							{
								Arrays.fill(b, -1);
							}
						}

						for(int z = 0; z <= Math.max(x - 1, 0) + Math.max(y - 1, 0); z++)
						{
							if(z % 2 == k % 2)
							{
								result += count(1, z, z >> 1);
							}
						}
					}
				}
			}
		}

		System.out.println(result);
	}

	public static long count(int index, int prev, int sum)
	{
		if(index == max)
		{
			if(prev <= 1 + (index <= min ? 1 : 0) && sum == (k >> index))
			{
				if(prev == 1 && index <= min)
				{
					return 2;
				}
				else
				{
					return 1;
				}
			}
			else
			{
				return 0;
			}
		}
		else if(memo[index][prev][sum] != -1)
		{
			return memo[index][prev][sum];
		}
		else
		{
			long count = 0;
			for(int i = 0; i <= 1 + (index <= min ? 1 : 0); i++)
			{
				if(prev - i >= 0 && ((prev - i + sum) & 1) == ((k >> index) & 1))
				{
					count += count(index + 1, prev - i, (prev - i + sum) >> 1);
					if(i == 1 && index <= min)
					{
						count += count(index + 1, prev - i, (prev - i + sum) >> 1);
					}
				}
			}

			return memo[index][prev][sum] = count;
		}
	}
}


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

public class CF {
    FastScanner in;
    PrintWriter out;

    long mod = (long) 1e9 + 7;

    void solve() {
//        for (int i = 1; i <= 10; i++) {
//            for (int j = 1; j <= 10; j++) {
//                System.err.print(sol2(i, j) - sol3(i, j) + " ");
//            }
//            System.err.println();
//        }
         out.println(sol2(in.nextInt(), in.nextInt()));
    }

    long sol2(int n, int m) {
        long res = 0;
        long[][] dp01 = new long[m + 1][n + 1];
        long[][] dp01Sum = new long[m + 1][n + 1];
        for (int w = 2; w <= m; w++)
            dp01[w][1] = 1;
        for (int h = 2; h <= n; h++)
            for (int w = 2; w <= m; w++) {
                dp01Sum[w][h] = (dp01Sum[w - 1][h] + dp01[w][h - 1]) % mod;
                dp01[w][h] = (dp01[w - 1][h] + dp01Sum[w][h]) % mod;
            }
        long[][] dp1 = new long[m + 1][n + 1];
        long[][] dp1Sum = new long[m + 1][n + 1];
        for (int w = 2; w <= m; w++)
            dp1[w][1] = 1;
        for (int h = 2; h <= n; h++)
            for (int w = 2; w <= m; w++) {
                dp1Sum[w][h] = (dp1Sum[w - 1][h] + dp01[w - 1][h - 1]) % mod;
                dp1[w][h] = (dp1[w - 1][h] + dp1Sum[w][h] + dp01[w - 1][h - 1]) % mod;
//                 for (int w1 = 2; w1 < w; w1++) {
//                 dp1[w][h] = (dp1[w][h] + (dp01[w1][h - 1] * (w - w1 + 1))
//                 % mod)
//                 % mod;
//                 }
            }
        long[][] dpSum01 = new long[m + 1][n + 1];
        for (int h = 1; h <= n; h++)
            for (int w = 1; w <= m; w++)
                dpSum01[w][h] = (dpSum01[w][h - 1] + dp01[w][h]) % mod;
        long[][] dpSum1 = new long[m + 1][n + 1];
        for (int h = 1; h <= n; h++)
            for (int w = 1; w <= m; w++)
                dpSum1[w][h] = (dpSum1[w][h - 1] + dp1[w][h]) % mod;
        for (int h1 = 1; h1 <= n; h1++)
            for (int w1 = 1; w1 <= m; w1++) {
                long curRes = (dpSum01[w1][h1] * dpSum1[w1][n - h1 + 1]) % mod;
                curRes = (curRes * (m - w1 + 1)) % mod;
                res = (res + curRes) % mod;
            }
        return res;
    }

    long sol3(int n, int m) {
        long res = 0;
        long[][] dp01 = new long[m + 1][n + 1];
        long[][] dp01Sum = new long[m + 1][n + 1];
        for (int w = 2; w <= m; w++)
            dp01[w][1] = 1;
        for (int h = 2; h <= n; h++)
            for (int w = 2; w <= m; w++) {
                dp01Sum[w][h] = (dp01Sum[w - 1][h] + dp01[w][h - 1]) % mod;
                dp01[w][h] = (dp01[w - 1][h] + dp01Sum[w][h]) % mod;
            }
        long[][] dp1 = new long[m + 1][n + 1];
        for (int w = 2; w <= m; w++)
            dp1[w][1] = 1;
        for (int h = 2; h <= n; h++)
            for (int w = 2; w <= m; w++) {
                for (int w1 = 2; w1 < w; w1++) {
                    dp1[w][h] = (dp1[w][h] + (dp01[w1][h - 1] * (w - w1 + 1))
                            % mod)
                            % mod;
                }
            }
        long[][] dp3 = new long[m + 1][n + 1];
        for (int h = 1; h <= n; h++)
            for (int w = 1; w <= m; w++) {
                for (int h1 = 1; h1 <= h; h1++) {
                    dp3[w][h] = (dp3[w][h] + (dp01[w][h1] * dp1[w][h - h1 + 1])
                            % mod)
                            % mod;

                }
                // dp3[w][h] = dp3[w][h - 1] + dp01[w][h] * dp1[w][h - h + 1];
            }
        for (int h = 1; h <= n; h++)
            for (int w = 1; w <= m; w++) {
                long curRes = (dp3[w][h] * (n - h + 1)) % mod;
                curRes = (curRes * (m - w + 1)) % mod;
                res = (res + curRes) % mod;
            }
        return res;
    }

    int stupid(int n, int m) {
        int total = n * m;
        int sum = 0;
        boolean[][] field = new boolean[n][m];
        for (int st = 0; st < (1 << total); st++) {
            int it = 0;
            for (int i = 0; i < n; i++)
                for (int j = 0; j < m; j++)
                    if (((1 << it++) & st) != 0)
                        field[i][j] = true;
                    else
                        field[i][j] = false;
            int l = -1, r = -1;
            boolean ok = true;
            int[] first = new int[n];
            int[] last = new int[n];
            Arrays.fill(first, -1);
            Arrays.fill(last, -1);
            for (int i = 0; i < n; i++) {
                int cnt = 0;
                for (int j = 0; j < m; j++)
                    if (field[i][j]) {
                        if (cnt == 0)
                            first[i] = j;
                        last[i] = j;
                        cnt++;
                    }
                if (cnt != 2 && cnt != 0)
                    ok = false;
                if (cnt == 2) {
                    r = i;
                    if (l == -1)
                        l = i;
                }
            }
            if (!ok)
                continue;
            if (l == -1 || r == -1)
                continue;
            for (int i = l; i <= r; i++)
                if (first[i] == -1 || last[i] == -1 || first[i] == last[i])
                    ok = false;
            if (!ok)
                continue;
            boolean ok2 = false;
            for (int t = l; t <= r; t++) {
                boolean ok3 = true;
                for (int i = l; i < t; i++) {
                    if (first[i] < first[i + 1] || last[i] > last[i + 1])
                        ok3 = false;
                }
                for (int i = r; i > t; i--)
                    if (first[i] < first[i - 1] || last[i] > last[i - 1])
                        ok3 = false;
                if (ok3)
                    ok2 = true;
            }
            if (ok2)
                sum++;
        }
        return sum;
    }

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

            solve();

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

    void runIO() {
        in = new FastScanner(System.in);
        out = new PrintWriter(System.out);

        solve();

        out.close();
    }

    class FastScanner {
        BufferedReader br;
        StringTokenizer st;

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

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

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

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

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

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

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
import java.io.PrintWriter;
import java.util.TreeMap;
public class E1113
{
    static class QN{
        int index;
        long sum;
        QN(int in,long an){
            index=in;
            sum=an;
        }
    }
    static class SegmentTree{
        long sum,pmin,lazy;
        int st,en;
        boolean rem;
        SegmentTree left,right;
        SegmentTree(int _st,int _en,long _v){
            st=_st;
            en=_en;
            lazy=_v;
            rem=true;
            sum=(en-st+1)*lazy;
            pmin=Math.min(lazy,sum);
        }
        long pmin(){
            return rem?(Math.min(lazy,(en-st+1)*lazy)):(pmin);
        }
        long sum(){
            return rem?((en-st+1)*lazy):(sum);
        }
        void update(int l,int r,long v){
            //completely outside
            if(l>en||r<st)
                return;
            //completely inside
            if(l<=st&&r>=en){
                //update lazy;
                lazy=v;
                rem=true;
                return;
            }
            //partial cover
            lazyPropagate();
            left.update(l, r, v);
            right.update(l, r, v);
            sum=left.sum()+right.sum();
            pmin=Math.min(left.pmin(),left.sum()+right.pmin());
            return;
        }
        void lazyPropagate(){
            if(left==null){
                int mid=(st+en)/2;
                left=new SegmentTree(st,mid,lazy);
                right=new SegmentTree(mid+1,en,lazy);
            }else if(rem){
                left.lazy=lazy;
                right.lazy=lazy;
                left.rem=true;
                right.rem=true;
            }
            if(rem){
                sum=left.sum()+right.sum();
                pmin=Math.min(left.pmin(),left.sum()+right.pmin());
            }
            rem=false;
        }
        /**returns least index which has value <= given value**/
        QN query(int l,int r,long v,long su){
            //no cover
            if(st>r||en<l)
                return new QN(-1,0);
            //full cover
            if(l<=st&&en<=r){
                if(su+pmin()<=v)
                    return query2(v,su);
                return new QN(-1,su+sum());
            }
            lazyPropagate();

            QN q1=left.query(l,r,v,su);
            if(q1.index!=-1)
                return q1;
            q1=right.query(l,r,v,q1.sum);
            return q1;
        }
        QN query2(long v,long su){
            if(st==en)
                return new QN(st,su+sum());
            lazyPropagate();
            if(left.pmin()+su<=v)
                return left.query2(v,su);
            else
                return right.query2(v,su+left.sum());

        }

    }
    static class Scanner
    {
        BufferedReader br;
        StringTokenizer tk=new StringTokenizer("");
        public Scanner(InputStream is)
        {
            br=new BufferedReader(new InputStreamReader(is));
        }
        public int nextInt() throws IOException
        {
            if(tk.hasMoreTokens())
                return Integer.parseInt(tk.nextToken());
            tk=new StringTokenizer(br.readLine());
            return nextInt();
        }
        public long nextLong() throws IOException
        {
            if(tk.hasMoreTokens())
                return Long.parseLong(tk.nextToken());
            tk=new StringTokenizer(br.readLine());
            return nextLong();
        }
        public String next() throws IOException
        {
            if(tk.hasMoreTokens())
                return (tk.nextToken());
            tk=new StringTokenizer(br.readLine());
            return next();
        }
        public String nextLine() throws IOException
        {
            tk=new StringTokenizer("");
            return br.readLine();
        }
        public double nextDouble() throws IOException
        {
            if(tk.hasMoreTokens())
                return Double.parseDouble(tk.nextToken());
            tk=new StringTokenizer(br.readLine());
            return nextDouble();
        }
        public char nextChar() throws IOException
        {
            if(tk.hasMoreTokens())
                return (tk.nextToken().charAt(0));
            tk=new StringTokenizer(br.readLine());
            return nextChar();
        }
        public int[] nextIntArray(int n) throws IOException
        {
            int a[]=new int[n];
            for(int i=0;i<n;i++)
                a[i]=nextInt();
            return a;
        }
        public long[] nextLongArray(int n) throws IOException
        {
            long a[]=new long[n];
            for(int i=0;i<n;i++)
                a[i]=nextLong();
            return a;
        }
        public int[] nextIntArrayOneBased(int n) throws IOException
        {
            int a[]=new int[n+1];
            for(int i=1;i<=n;i++)
                a[i]=nextInt();
            return a;
        }
        public long[] nextLongArrayOneBased(int n) throws IOException
        {
            long a[]=new long[n+1];
            for(int i=1;i<=n;i++)
                a[i]=nextLong();
            return a;
        }

    }

    public static void main(String args[]) throws IOException
    {
        Scanner in=new Scanner(System.in);
        PrintWriter out=new PrintWriter(System.out);
        SegmentTree st=new SegmentTree(1,1000000000,0);
        int q=in.nextInt();
        TreeMap<Integer,Integer> mp=new TreeMap<>();
        mp.put(0,0);
        mp.put(1000000001,0);
        while(q--!=0){
            int tp=in.nextInt();
            switch(tp){
                case 1:
                    int tm=in.nextInt();
                    int vl=in.nextInt();
                    int nxt=mp.higherKey(tm)-1;
                    st.update(tm, nxt, vl);
                    mp.put(tm,vl);
                    break;
                case 2:
                    int tc=in.nextInt();
                    int vp=mp.lowerEntry(tc).getValue();
                    int net=mp.higherKey(tc)-1;
                    st.update(tc, net, vp);
                    mp.remove(tc);
                    break;
                case 3:
                    int l=in.nextInt();
                    int lc=l;
                    l=mp.ceilingKey(l);
                    int r=in.nextInt();
                    int v=in.nextInt();
                    if(v==0){
                        out.println(lc);
                        continue;
                    }
                    if(l>=r){
                        out.println(-1);
                        continue;
                    }
                    QN aa=st.query(l, r-1, -v, 0);
                    if(aa.index==-1)
                        out.println(-1);
                    else{
                        int spd=mp.floorEntry(aa.index).getValue();
                        double remv=-(v+(aa.sum-spd));
                        double anss=aa.index;
                        anss+=remv/spd;
                        out.println(anss);

                    }

            }

        }
        out.close();
    }

}


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.math.BigDecimal;
import java.math.MathContext;
import java.math.RoundingMode;
import java.text.DecimalFormat;
import java.util.Arrays;
import java.util.StringTokenizer;

public class d {
    static double EPS = 1e-6    ;
    public static void main(String[] args) {
        FS in = new FS(System.in);
        PrintWriter out = new PrintWriter(System.out);

        int n = in.nextInt();

        Vec com = new Vec(0, 0);
        Vec[] vecs = new Vec[n];
        for(int i = 0; i < n; i++) {
            com = com.add(vecs[i] = new Vec(in.nextInt(), in.nextInt()));
        }
        com = com.scaleR(n);

        boolean[] works = new boolean[n];
        Arrays.fill(works, true);
        int num = n;
        for(int i = 0; i < n; i++) {
            if(vecs[i].equals(com)) {
                works[i] = false;
                num--;
                continue;
            }
            for(int j = 0; j < i; j++) {
                if(works[j] && vecs[i].sub(com).equals(com.sub(vecs[j]))) {
                    works[i] = works[j] = false;
                    num -= 2;
                    break;
                }
            }
        }
        Vec[] act = new Vec[num];
        int curr = 0;
        for(int i = 0; i < n; i++) if(works[i]) act[curr++] = vecs[i];
        n = num;
        if(n == 0) {
            System.out.println(-1);
            return;
        }
        int res = 0;

        Vec[] norms = new Vec[n];

        outer: for(int i = 0; i < n; i++) {
            Vec diff = act[i].sub(act[0]);
            Vec mid = act[0].add(diff.scaleR(2));
            Vec perp = com.sub(mid).rot90();
            if(perp.equals(new Vec(0, 0))) continue;
            Vec norm = perp;
            norm = norm.scaleR(Math.sqrt(norm.dot(norm)));
            if(norm.x < 0 || (eq(norm.x, 0) && norm.y < 0)) {
                norm.x *= -1;
                norm.y *= -1;
            }
            norms[i] = norm;
            for(int j = 0; j < i; j++) {
                if(norms[j].equals(norm)) continue outer;
            }
            double[] arr = new double[n];
            for(int j = 0; j < n; j++) arr[j] = perp.dot(act[j]);
            Arrays.sort(arr);
            double cent = (arr[0]+arr[n-1])/2;
            for(int j = 0; j < n; j++) {
                if(!eq(cent-arr[j], arr[n-1-j]-cent)) continue outer;
            }
            res++;
        }
        System.out.println(res);
        out.close();
    }

    static class Vec {
        double x, y;

        public Vec(double A, double B) {
            x = A;
            y = B;
        }

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

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

        public Vec scale(double s) {
            return new Vec(x*s, y*s);
        }

        public Vec scaleR(double s) {
            return new Vec(x/s, y/s);
        }

        public Vec rot90() {
            return new Vec(-y, x);
        }

        public double dot(Vec o) {
            return x*o.x + y*o.y;
        }

        @Override
        public boolean equals(Object o) {
            return eq(x, ((Vec)o).x) && eq(y, ((Vec)o).y);
        }
    }

    static boolean eq(double a, double b) {
        return Math.abs(a-b) <= EPS;
    }

    static class FS {
        BufferedReader in;
        StringTokenizer token;

        public FS(InputStream str) {
            in = new BufferedReader(new InputStreamReader(str));
        }

        public String next() {
            if(token == null || !token.hasMoreElements()) {
                try {
                    token = new StringTokenizer(in.readLine());
                } catch (IOException ex) {
                }
                return next();
            }
            return token.nextToken();
        }

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


import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Scanner;
import java.util.StringTokenizer;
import java.util.TreeSet;

public class D {
    static ArrayList[] adj;
    static ArrayList[] rev;
    static BufferedReader in;
    static StringTokenizer st;

    static class pr implements Comparable<pr> {
        int v;

        pr(int x) {
            v = x;
        }

        @Override
        public int compareTo(pr o) {
            if (o.v == v) return 0;
            if (d[o.v] < d[v]) return 1;
            return -1;
        }
    }

    static int d[];

    public static void main(String[] args) throws IOException {
        in = new BufferedReader(new InputStreamReader(System.in));
        fp();
        int n = nextInt();
        int m = nextInt();
        adj = new ArrayList[n];
        rev = new ArrayList[n];
        for (int i = 0; i < n; i++) {
            adj[i] = new ArrayList();
            rev[i] = new ArrayList();
        }
        for (int i = 0; i < m; i++) {
            fp();
            int a = nextInt() - 1;
            int b = nextInt() - 1;
            adj[a].add(b);
            rev[b].add(a);
        }
        fp();
        int k = nextInt();
        int ms[] = new int[k];
        fp();
        for (int i = 0; i < k; i++) {
            ms[i] = nextInt() - 1;
        }
        int fn = ms[k - 1];
        d = new int[n];
        int inf = 1000_000_000;
        for (int i = 0; i < n; i++) {
            d[i] = inf;
        }
        d[fn] = 0;
        TreeSet<pr> set = new TreeSet<pr>();
        set.add(new pr(fn));
        while (!set.isEmpty()) {
            pr tk = set.first();
            set.remove(tk);
            for (int i = 0; i < rev[tk.v].size(); i++) {
                int to = (int) rev[tk.v].get(i);
                if (d[to] > d[tk.v] + 1) {
                    set.remove(new pr(to));
                    d[to] = d[tk.v] + 1;
                    set.add(new pr(to));
                }
            }
        }
        int mn = 0;
        int mx = 0;
        for (int i = 0; i < k - 1; i++) {
            if (d[ms[i]] == d[ms[i + 1]] + 1) {
                for (int j = 0; j < adj[ms[i]].size(); j++) {
                    int to = (int) adj[ms[i]].get(j);
                    if (to != ms[i + 1]) {
                        if (d[to] + 1 == d[ms[i]]) {
                            mx++;
                            break;
                        }
                    }
                }
            } else {
                mn++;
                mx++;
            }
        }
        System.out.println(mn + " " + mx);
    }

    private static void fp() throws IOException {
        st = new StringTokenizer(in.readLine());
    }

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


import java.util.*;
public class f {
public static void main(String[] args)
{
    Scanner input = new Scanner(System.in);
    long a = input.nextLong(), b = input.nextLong();
    int k = input.nextInt();
    int lcm = 1;
    for(int i = 2; i<=k; i++) lcm = lcm(lcm, i);
    int[] dp = new int[2*lcm];
    int start = (int)(a%lcm) + lcm;
    Arrays.fill(dp, 987654321);
    dp[start] = 0;
    for(int i = start; i>0; i--)
    {
        dp[i-1] = Math.min(dp[i-1], dp[i]+1);
        for(int j = 2; j<=k; j++)
        {
            int next = i - i%j;
            if(next >= 0) dp[next] = Math.min(dp[next], dp[i]+1);
        }
    }
    long res = 0;
    if(a-b >= lcm)
    {
        res = dp[lcm];
        a -= (a%lcm);
    }
    //System.out.println(dp[0]+" "+dp[lcm]);
    int lcmStep = dp[0]-dp[lcm];
    //System.out.println(lcm+" "+lcmStep);

    long numSteps = (a-b)/lcm - 2;
    if(numSteps > 0)
    {
        a -= lcm*numSteps;
        res += lcmStep*numSteps;
    }

    dp = new int[5*lcm];
    int end = (int)(b - lcm*(b/lcm));
    start = (int)(end + a - b);
    //System.out.println(start+" "+end);
    Arrays.fill(dp, 987654321);
    dp[start] = 0;
    for(int i = start; i>end; i--)
    {
        dp[i-1] = Math.min(dp[i-1], dp[i]+1);
        for(int j = 2; j<=k; j++)
        {
            int next = i - i%j;
            if(next > 0) dp[next] = Math.min(dp[next], dp[i]+1);
        }
    }

    res += dp[end];

    System.out.println(res);
}
static int lcm(int a, int b)
{
    return a/gcd(a,b)*b;
}
static int gcd(int a, int b)
{
    if(b==0) return a;
    return gcd(b, a%b);
}
}


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

public class Main implements Runnable {
	BufferedReader in;
	PrintStream out;
	StringTokenizer st = new StringTokenizer("");
	double eps = 1e-9;

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

	void printExit(String s) {
		System.out.println(s);
		System.exit(0);
	}

	Point readPoint() {
		return new Point(nextDouble(), nextDouble());
	}

	class Point {
		double x, y;

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

		Point subtract(Point rhs) {
			return new Point(x - rhs.x, y - rhs.y);
		}

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

		Point rotate() {
			return new Point(-y, x);
		}

		double len() {
			return hypot(x, y);
		}

		Point normalize() {
			return new Point(x / len(), y / len());
		}

		Point mult(double c) {
			return new Point(x * c, y * c);
		}

		//distance from the line
		double dist(Point X, Point Y) {
			double S = abs(square(this, X, Y));
			return S / X.subtract(Y).len();
		}

		boolean liesOn(Point X, Point Y) {
			double S = abs(square(this, X, Y));
			return (interon(x, X.x, Y.x) && interon(y, X.y, Y.y) && S < eps);
		}
	}

	double dist(Point X, Point Y) {
		return Y.subtract(X).len();
	}

	Point get(Point X, Point Y, double c) {
		return X.add(Y.subtract(X).mult(c));
	}

	double square(Point a, Point b, Point c) {
		return a.x * (b.y - c.y) + b.x * (c.y - a.y) + c.x * (a.y - b.y);
	}

	boolean interon(double x1, double x2, double y1, double y2) {
		return max(x1, x2) + eps >= min(y1, y2) && max(y1, y2) + eps >= min(x1, x2);
	}

	boolean interon(double x, double x1, double x2) {
		return x + eps >= min(x1, x2) && x <= max(x1, x2) + eps;
	}

	boolean intersect(Point a1, Point a2, Point b1, Point b2) {
		double s1 = square(a1, b1, b2), s2 = square(a2, b1, b2);
		double s3 = square(b1, a1, a2), s4 = square(b2, a1, a2);
		if (s1 * s2 < -eps && s3 * s4 < -eps) return true;
		if (a1.liesOn(b1, b2) || a2.liesOn(b1, b2) || b1.liesOn(a1, a2) || b2.liesOn(a1, a2))
			return true;
		//if (abs(s1) < eps && abs(s2) < eps && abs(s3) < eps && abs(s4) < eps)
		//	return interon(a1.x, a2.x, b1.x, b2.x) && interon(a1.y, a2.y, b1.y, b2.y);
		return false;
	}

	//STRICT INNER INTERSECTION. it is allowed to have common point or lie on common line
	boolean intersectH(Point a1, Point a2, Point b1, Point b2) {
		double s1 = square(a1, b1, b2), s2 = square(a2, b1, b2);
		double s3 = square(b1, a1, a2), s4 = square(b2, a1, a2);
		if (s1 * s2 < -eps && s3 * s4 < -eps) return true;
		return false;
	}

	boolean parallel(Point a1, Point a2, Point b1, Point b2) {
		double s1 = square(a1, b1, b2), s2 = square(a2, b1, b2);
		double s3 = square(b1, a1, a2), s4 = square(b2, a1, a2);
		return (abs(s1) < eps && abs(s2) < eps && abs(s3) < eps && abs(s4) < eps);
	}

	public void run() {
		try {
			Locale.setDefault(Locale.US);
			in = new BufferedReader(new InputStreamReader(System.in));
			out = new PrintStream(System.out);

			Point V = readPoint(), P = readPoint();
			Point [] W = new Point[2], M = new Point[2];
			for (int i = 0; i < 2; i++)
				W[i] = readPoint();
			for (int i = 0; i < 2; i++)
				M[i] = readPoint();

			if (!intersect(V, P, W[0], W[1])) {
			        if (intersect(V, P, M[0], M[1]) && !parallel(V, P, M[0], M[1])) printExit("NO");
			        else printExit("YES");
			}
			//now wall is on the V-P path and mirror - not

			double s1 = square(P, M[0], M[1]), s2 = square(V, M[0], M[1]);
			if (s1 * s2 < eps) printExit("NO");
			//V and P -> strictly by one side of the line

			Point N = M[1].subtract(M[0]).rotate().normalize();
			double d = V.dist(M[0], M[1]);

			//System.out.println(d);
			Point MV = V.add(N.mult(2 * d));
			if (!intersect(MV, P, M[0], M[1]))
				MV = V.add(N.mult(-2 * d));
			if (!intersect(MV, P, M[0], M[1]))
				printExit("NO");

			double l = 0, r = 1;
			for (int i = 0; i < 200; i++) {
				double m1 = (2 * l + r) / 3, m2 = (l + 2 * r) / 3;
				Point M1 = get(M[0], M[1], m1), M2 = get(M[0], M[1], m2);
				double d1 = dist(MV, M1) + dist(P, M1), d2 = dist(MV, M2) + dist(P, M2);
				if (d1 > d2) l = m1;
					else r = m2;
			}

			Point T = get(M[0], M[1], l);
			if (!intersect(P, T, W[0], W[1]) && !intersect(T, V, W[0], W[1])) printExit("YES");
			printExit("NO");

		}
		catch (Exception e) {
			e.printStackTrace();
		}
	}

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

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

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

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

 	 BigInteger nextBigInteger() {
 	 	return new BigInteger(nextToken());
 	}

 	 String nextToken() {
 	 	seekForToken();
 	 	return st.nextToken();
 	}

}


import java.io.OutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Arrays;
import java.io.BufferedWriter;
import java.io.Writer;
import java.io.OutputStreamWriter;
import java.util.InputMismatchException;
import java.io.IOException;
import java.io.InputStream;

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

    static class GTakeMetro {
        public void solve(int testNumber, InputReader in, OutputWriter out) {
            int n = in.nextInt(), m = in.nextInt();
            int s = in.nextInt() - 1;
            long t = in.nextLong();
            while (t % n != 0) {
                if (s < m) {
                    s = (int) ((s + t) % n);
                } else {
                    s = (int) ((s - t) % n);
                    if (s < 0) s += n;
                }
                t--;
            }
            t /= n;
            int[] seen = new int[n];
            Arrays.fill(seen, -1);
            seen[s] = 0;
            int count = 0;
            while (t-- > 0) {
                count++;
                for (int i = n - 1; i >= 1; i--) {
                    if (s < m) {
                        s = (s + i) % n;
                    } else {
                        s = (s - i + n) % n;
                    }
                }
                if (seen[s] != -1) {
                    t %= (count - seen[s]);
                }
                seen[s] = count;
            }
            out.println(s + 1);
        }

    }

    static class OutputWriter {
        private final PrintWriter writer;

        public OutputWriter(OutputStream outputStream) {
            writer = new PrintWriter(new BufferedWriter(new OutputStreamWriter(outputStream)));
        }

        public OutputWriter(Writer writer) {
            this.writer = new PrintWriter(writer);
        }

        public void close() {
            writer.close();
        }

        public void println(int i) {
            writer.println(i);
        }

    }

    static class InputReader {
        private InputStream stream;
        private byte[] buf = new byte[1 << 16];
        private int curChar;
        private int numChars;

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

        public int read() {
            if (this.numChars == -1) {
                throw new InputMismatchException();
            } else {
                if (this.curChar >= this.numChars) {
                    this.curChar = 0;

                    try {
                        this.numChars = this.stream.read(this.buf);
                    } catch (IOException var2) {
                        throw new InputMismatchException();
                    }

                    if (this.numChars <= 0) {
                        return -1;
                    }
                }

                return this.buf[this.curChar++];
            }
        }

        public int nextInt() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            int res = 0;

            while (c >= 48 && c <= 57) {
                res *= 10;
                res += c - 48;
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * sgn;
                }
            }

            throw new InputMismatchException();
        }

        public long nextLong() {
            int c;
            for (c = this.read(); isSpaceChar(c); c = this.read()) {
                ;
            }

            byte sgn = 1;
            if (c == 45) {
                sgn = -1;
                c = this.read();
            }

            long res = 0L;

            while (c >= 48 && c <= 57) {
                res *= 10L;
                res += (long) (c - 48);
                c = this.read();
                if (isSpaceChar(c)) {
                    return res * (long) sgn;
                }
            }

            throw new InputMismatchException();
        }

        public static boolean isSpaceChar(int c) {
            return c == 32 || c == 10 || c == 13 || c == 9 || c == -1;
        }

    }
}


import java.util.*;
public class d {
	public static void main(String[] arg) {
		new d();
	}
	public d() {
		Scanner in = new Scanner(System.in);
		int n = in.nextInt();
		int[] smallestPrime = new int[n+1];
		boolean[] isPrime = new boolean[n+1];
		Arrays.fill(isPrime, true);
		isPrime[0] = isPrime[1] = false;
		for(int i = 2; i < isPrime.length; i++) {
			if(isPrime[i]) {
				smallestPrime[i] = i;
				for(int j = i+i; j < isPrime.length; j+=i) {
					isPrime[j] = false;
					if(smallestPrime[j] == 0) smallestPrime[j] = i;
				}
			}
		}
		long[] numP = new long[n+1];
		for(int i = 2; i <= n; i++) {
			numP[smallestPrime[i]]++;
		}
		long[] cum = new long[n+1];
		cum[0] = numP[0];
		for(int i = 1; i <= n; i++) {
			cum[i] += cum[i-1]+numP[i];
		}
		long count2 = 1L * n * (n - 1) / 2 - (n - 1);
		long ans = 0;
		/*
		for(int i = 2; i <= n; i++) {
			int p = smallestPrime[i];
			int other = i/p;
			if(isPrime[other] && other > p) {
//				System.out.println(i + " " + other + " " + numP[p] + " " + numP[other]);
				long temp = numP[p]*numP[other];
				for(int j = p; j <= n; j+=p) {
					if(j % other == 0 && smallestPrime[j] == p)
						temp -= numP[other];
				}
				ans += 2*temp;
			}
		}*/
		outer:
		for(int i = 2; i <= n; i++) {
			long count = 0;
			int sign = -1;
			int x = i;
			while(x > 1) {
				int y = smallestPrime[x];
				x /= y;
				if(smallestPrime[x] == y) {
					continue outer;
				}
				sign *= -1;
			}
			for(int j = i; j <= n; j += i) {
				count++;
			}
			count2 -= sign*(count*(count-1)/2);
			ans += sign*(count*(count-1)/2);
		}
		for(int i = 2; i <= n; i++) {
			if(!isPrime[i]) continue;
			if(n / 2 <= i) continue;
			long c = cum[n / 2];
			c -= cum[Math.max(n / i, i)];
			ans += numP[i]*c*3;
			count2 -= numP[i]*c;
		}
		//System.err.println(count2);
		long numSpec = 0;
		for (int i = 2; i <= n; i++) {
			if (smallestPrime[i] * 2 > n) {
				numSpec++;
			}
		}
		count2 -= (n - 2) * numSpec;
		count2 += numSpec * (numSpec - 1) / 2;
		//System.err.println(count2);
		ans += count2 * 2;
		System.out.println(ans);
	}
}


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

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

	void solve()
	{
		int n = ni(), m = ni(), K = ni();
		boolean[][] g = new boolean[n][n];
		for(int i = 0;i < m;i++){
			int f = ni()-1, t = ni()-1;
			g[f][t] = g[t][f] = true;
		}
		int[][] dp = new int[1<<n][1<<n];
		for(int i = 0;i < n;i++){
			for(int j = i+1;j < n;j++){
				if(g[i][j]){
					dp[1<<i|1<<j][1<<i|1<<j] = 1;
				}
			}
		}
		for(int i = 0;i < 1<<n;i++){
			if(Integer.bitCount(i) <= 1)continue;
			for(int j = 0;j <= i;j++){
				if((i&j)==j){
					if(Integer.bitCount(i) >= 3 && j > 0)dp[i][j] /= Integer.bitCount(j);
					for(int k = 0;k < n;k++){
						if(i<<31-k>=0){
							for(int l = 0;l < n;l++){
								if(i<<31-l<0 && g[l][k]){
									dp[i|1<<k][j&~(1<<l)|1<<k] += dp[i][j];
								}
							}
						}
					}
				}
			}
		}

		long S = 0;
		for(int j = 0;j < 1<<n;j++){
			if(Integer.bitCount(j) == K){
				S += dp[(1<<n)-1][j];
			}
		}
		out.println(S);
	}

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

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

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

	public int ni()
	{
		try {
			int num = 0;
			boolean minus = false;
			while((num = is.read()) != -1 && !((num >= '0' && num <= '9') || num == '-'));
			if(num == '-'){
				num = 0;
				minus = true;
			}else{
				num -= '0';
			}

			while(true){
				int b = is.read();
				if(b >= '0' && b <= '9'){
					num = num * 10 + (b - '0');
				}else{
					return minus ? -num : num;
				}
			}
		} catch (IOException e) {
		}
		return -1;
	}

	public long nl()
	{
		try {
			long num = 0;
			boolean minus = false;
			while((num = is.read()) != -1 && !((num >= '0' && num <= '9') || num == '-'));
			if(num == '-'){
				num = 0;
				minus = true;
			}else{
				num -= '0';
			}

			while(true){
				int b = is.read();
				if(b >= '0' && b <= '9'){
					num = num * 10 + (b - '0');
				}else{
					return minus ? -num : num;
				}
			}
		} catch (IOException e) {
		}
		return -1;
	}

	public String ns()
	{
		try{
			int b = 0;
			StringBuilder sb = new StringBuilder();
			while((b = is.read()) != -1 && (b == '\r' || b == '\n' || b == ' '));
			if(b == -1)return "";
			sb.append((char)b);
			while(true){
				b = is.read();
				if(b == -1)return sb.toString();
				if(b == '\r' || b == '\n' || b == ' ')return sb.toString();
				sb.append((char)b);
			}
		} catch (IOException e) {
		}
		return "";
	}

	public char[] ns(int n)
	{
		char[] buf = new char[n];
		try{
			int b = 0, p = 0;
			while((b = is.read()) != -1 && (b == ' ' || b == '\r' || b == '\n'));
			if(b == -1)return null;
			buf[p++] = (char)b;
			while(p < n){
				b = is.read();
				if(b == -1 || b == ' ' || b == '\r' || b == '\n')break;
				buf[p++] = (char)b;
			}
			return Arrays.copyOf(buf, p);
		} catch (IOException e) {
		}
		return null;
	}

	double nd() { return Double.parseDouble(ns()); }
	boolean oj = System.getProperty("ONLINE_JUDGE") != null;
	void tr(Object... o) { if(!oj)System.out.println(Arrays.deepToString(o)); }
}


import java.util.*;

public class TaskF {
    private static final long MOD = 1_000_000_000 + 7;

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

        int n = in.nextInt();
        int m = in.nextInt();

        initFactorials(Math.max(n, m));
        System.out.println(solve(n, m));

        in.close();
    }

    private static long solve(int n, int m) {
        long sum = 0;
        for (int k = 1; k <= n - 1; k++) {
            long splits = splits(m, k);
            long perms = perms(n, k);
            long rest = rest(n, m, k);
            sum += (((splits * perms) % MOD) * rest) % MOD;
            sum = sum % MOD;
        }
        return sum;
    }

    private static long splits(int sum, int count) {
        return modCombinations(sum - 1, count - 1);
    }

    private static long perms(int n, int k) {
        return modKPermutations(n - 2, k - 1);
    }

    private static long rest(int n, int m, int k) {
        return (modNumberOfTrees(n, k + 1) * modPower(m, n - 1 - k)) % MOD;
    }

    private static long modNumberOfTrees(int n, int y) {
        if (n < y) {
            return 0;
        } else if (n == y) {
            return 1;
        } else {
            return (y * modPower(n, n - y - 1)) % MOD;
        }
    }

    private static long[] factorial;
    private static long[] inverse;
    private static long[] inverseFactorial;

    private static void initFactorials(int upTo) {
        factorial = new long[upTo + 1];
        inverse = new long[upTo + 1];
        inverseFactorial = new long[upTo + 1];
        factorial[0] = 1;
        factorial[1] = 1;
        for (int i = 2; i <= upTo; i++) {
            factorial[i] = (factorial[i - 1] * i) % MOD;
        }
        inverse[0] = 1;
        inverse[1] = 1;
        for (int i = 2; i <= upTo; i++) {
            inverse[i] = (MOD - (MOD / i) * inverse[(int)MOD % i] % MOD) % MOD;
        }
        inverseFactorial[0] = inverse[0];
        for (int i = 1; i <= upTo; i++) {
            inverseFactorial[i] = (inverseFactorial[i - 1] * inverse[i]) % MOD;
        }
    }

    private static long modKPermutations(int n, int k) {
        if (n < k) return 0;
        return (factorial[n] * inverseFactorial[n - k]) % MOD;
    }

    private static long modCombinations(int n, int k) {
        if (n < k) return 0;
        return (((factorial[n] * inverseFactorial[k]) % MOD) * inverseFactorial[n - k]) % MOD;
    }

    private static long modPower(int n, int p) {
        if (p == 0) {
            return 1;
        } else if (p % 2 == 1) {
            return (n * modPower(n, p - 1)) % MOD;
        } else {
            long halfPower = modPower(n, p / 2);
            return (halfPower * halfPower) % MOD;
        }
    }

    private static long modRestoreFactorMapToNumber(Map<Integer, Integer> factorMap) {
        long result = 1;
        for (int prime : factorMap.keySet()) {
            result = (result * modPower(prime, factorMap.get(prime))) % MOD;
        }
        return result;
    }

    private static class MapTools {
        public Map<Integer, Integer> subtractCounts(
                Map<Integer, Integer> a, Map<Integer, Integer> b) {

            Map<Integer, Integer> result = new HashMap<>(a);

            for (int bKey : b.keySet()) {
                if (!result.containsKey(bKey)) {
                    throw new RuntimeException("No such key: " + bKey);
                }
                result.put(bKey, result.get(bKey) - b.get(bKey));
            }

            return result;
        }
    }

    private static class Primes {
        private final List<Integer> primes = new ArrayList<>();
        private int primesLimit;

        private final Map<Integer, Map<Integer, Integer>> factorialFactorizationCache = new HashMap<>();
        public Map<Integer, Integer> factorFactorial(int n) {
            return factorialFactorizationCache.computeIfAbsent(n, $ -> {
                calculatePrimesUpTo(n);
                Map<Integer, Integer> result = new HashMap<>();
                for (int p : primes) {
                    if (p > n) break;
                    int count = 0;
                    int pPower = p;
                    while (pPower <= n) {
                        count += n / pPower;
                        pPower *= p;
                    }
                    result.put(p, count);
                }
                return result;
            });
        }

        private void calculatePrimesUpTo(int newLimit) {
            if (newLimit <= primesLimit) return;

            int start = primesLimit + 1;
            if (start <= 2) {
                start = 2;
            }
            for (int i = start; i <= newLimit; i++) {
                if (isPrime(i)) {
                    primes.add(i);
                }
            }

            primesLimit = newLimit;
        }

        private boolean isPrime(int n) {
            for (int p : primes) {
                if (p * p > n) break;
                if (n % p == 0) return false;
            }
            return true;
        }
    }
}