import java.util.*; import java.io.*; import java.math.*; import java.util.function.*; public class Main implements Runnable { static boolean DEBUG; public static void main(String[] args) { DEBUG = args.length > 0 && args[0].equals("-DEBUG"); Thread.setDefaultUncaughtExceptionHandler((t, e) -> { e.printStackTrace(); System.exit(1); }); new Thread(null, new Main(), "", 1 << 31).start(); } public void run() { Solver solver = new Solver(); solver.solve(); solver.exit(); } static class FastScanner { private final InputStream in = System.in; private final byte[] buffer = new byte[1024]; private int pointer = 0; private int buflen = 0; private boolean hasNextByte() { if(pointer < buflen) return true; else { pointer = 0; try { buflen = in.read(buffer); }catch (IOException e) { e.printStackTrace(); } return buflen > 0; } } private int readByte() { if(hasNextByte()) return buffer[pointer ++]; else return -1; } private boolean isPrintableChar(int c) { return isPrintableChar(c, false); } private boolean isPrintableChar(int c, boolean includingSpace) { return (includingSpace ? 32 : 33) <= c && c <= 126; } private void skipUnprintable() { skipUnprintable(false); } private void skipUnprintable(boolean includingSpace) { while(hasNextByte() && !isPrintableChar(buffer[pointer], includingSpace)) pointer++; } private boolean hasNext() { return hasNext(false); } private boolean hasNext(boolean includingSpace) { skipUnprintable(includingSpace); return hasNextByte(); } private StringBuilder sb = new StringBuilder(); public String next() { return next(false); } public String next(boolean includingSpace) { if(!hasNext(includingSpace)) throw new NoSuchElementException(); sb.setLength(0); int b = readByte(); while(isPrintableChar(b, includingSpace)) { sb.appendCodePoint(b); b = readByte(); } return sb.toString(); } public long nextLong() { 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 = n * 10 + b - '0'; else if(b == -1 || !isPrintableChar(b)) return minus ? -n : n; else throw new NumberFormatException(); b = readByte(); } } } static class Solver { FastScanner sc = new FastScanner(); public Solver() { } String ns() { return ns(false); } String ns(boolean includingSpace) { return sc.next(includingSpace); } String[] ns(int n) { return ns(n, false); } String[] ns(int n, boolean includingSpace) { String a[] = new String[n]; for(int i = 0; i < n; i ++) a[i] = ns(includingSpace); return a; } String[][] ns(int n, int m) { return ns(n, m, false); } String[][] ns(int n, int m, boolean includingSpace) { String a[][] = new String[n][m]; for(int i = 0; i < n; i ++) a[i] = ns(m, includingSpace); return a; } char nc() { return ns().charAt(0); } char[] nc(int n) { String str = ns(); if(n < 0) n = str.length(); char a[] = new char[n]; for(int i = 0; i < n; i ++) a[i] = str.charAt(i); return a; } char[][] nc(int n, int m) { char a[][] = new char[n][m]; for(int i = 0; i < n; i ++) a[i] = nc(m); return a; } boolean[] nb(int n, char t) { char c[] = nc(-1); if(n < 0) n = c.length; boolean a[] = new boolean[n]; for(int i = 0; i < n; i ++) a[i] = c[i] == t; return a; } boolean[][] nb(int n, int m, char t) { boolean a[][] = new boolean[n][m]; for(int i = 0; i < n; i ++) a[i] = nb(m, t); return a; } int ni() { return Math.toIntExact(sc.nextLong()); } int[] ni(int n) { int a[] = new int[n]; for(int i = 0; i < n; i ++) a[i] = ni(); return a; } int[][] ni(int n, int m) { int a[][] = new int[n][m]; for(int i = 0; i < n; i ++) a[i] = ni(m); return a; } long nl() { return sc.nextLong(); } long[] nl(int n) { long a[] = new long[n]; for(int i = 0; i < n; i ++) a[i] = nl(); return a; } long[][] nl(int n, int m) { long a[][] = new long[n][m]; for(int i = 0; i < n; i ++) a[i] = nl(m); return a; } double nd() { return Double.parseDouble(sc.next()); } double[] nd(int n) { double a[] = new double[n]; for(int i = 0; i < n; i ++) a[i] = nd(); return a; } double[][] nd(int n, int m) { double a[][] = new double[n][m]; for(int i = 0; i < n; i ++) a[i] = nd(m); return a; } String booleanToString(boolean b) { return b ? "#" : "."; } PrintWriter out = new PrintWriter(System.out); PrintWriter err = new PrintWriter(System.err); StringBuilder sb4prtln = new StringBuilder(); void prt() { out.print(""); } void prt(T a) { out.print(a); } void prtln() { out.println(""); } void prtln(T a) { out.println(a); } void prtln(int... a) { sb4prtln.setLength(0); for(int element : a) sb4prtln.append(element+" "); prtln(sb4prtln.toString().trim()); } void prtln(long... a) { sb4prtln.setLength(0); for(long element : a) sb4prtln.append(element+" "); prtln(sb4prtln.toString().trim()); } void prtln(double... a) { sb4prtln.setLength(0); for(double element : a) sb4prtln.append(element+" "); prtln(sb4prtln.toString().trim()); } void prtln(String... a) { sb4prtln.setLength(0); for(String element : a) sb4prtln.append(element+" "); prtln(sb4prtln.toString().trim()); } void prtln(char... a) { sb4prtln.setLength(0); for(char element : a) sb4prtln.append(element); prtln(sb4prtln.toString()); } void prtln(boolean... a) { sb4prtln.setLength(0); for(boolean element : a) sb4prtln.append(booleanToString(element)); prtln(sb4prtln.toString()); } void prtln(int[][] a) { for(int[] element : a) prtln(element); } void prtln(long[][] a) { for(long[] element : a) prtln(element); } void prtln(double[][] a) { for(double[] element : a) prtln(element); } void prtln(String[][] a) { for(String[] element : a) prtln(element); } void prtln(char[][] a) { for(char[] element : a) prtln(element); } void prtln(boolean[][] a) { for(boolean[] element : a) prtln(element); } String errconvert(int a) { return isINF(a) ? "_" : String.valueOf(a); } String errconvert(long a) { return isINF(a) ? "_" : String.valueOf(a); } void errprt(int a) { if(DEBUG) err.print(errconvert(a)); } void errprt(long a) { if(DEBUG) err.print(errconvert(a)); } void errprt() { if(DEBUG) err.print(""); } void errprt(T a) { if(DEBUG) err.print(a); } void errprt(boolean a) { if(DEBUG) errprt(booleanToString(a)); } void errprtln() { if(DEBUG) err.println(""); } void errprtln(int a) { if(DEBUG) err.println(errconvert(a)); } void errprtln(long a) { if(DEBUG) err.println(errconvert(a)); } void errprtln(T a) { if(DEBUG) err.println(a); } void errprtln(boolean a) { if(DEBUG) errprtln(booleanToString(a)); } void errprtln(int... a) { if(DEBUG) { sb4prtln.setLength(0); for(int element : a) sb4prtln.append(errconvert(element)+" "); errprtln(sb4prtln.toString().trim()); } } void errprtln(long... a) { if(DEBUG) { sb4prtln.setLength(0); for(long element : a) sb4prtln.append(errconvert(element)+" "); errprtln(sb4prtln.toString().trim()); } } void errprtln(double... a) { if(DEBUG) { sb4prtln.setLength(0); for(double element : a) sb4prtln.append(element+" "); errprtln(sb4prtln.toString().trim()); } } void errprtln(String... a) { if(DEBUG) { sb4prtln.setLength(0); for(String element : a) sb4prtln.append(element+" "); errprtln(sb4prtln.toString().trim()); } } void errprtln(char... a) { if(DEBUG) { sb4prtln.setLength(0); for(char element : a) sb4prtln.append(element); errprtln(sb4prtln.toString()); } } void errprtln(boolean... a) { if(DEBUG) { sb4prtln.setLength(0); for(boolean element : a) sb4prtln.append(booleanToString(element)); errprtln(sb4prtln.toString()); } } void errprtln(Object[] a) { if(DEBUG) for(Object element : a) errprtln(element); } void errprtln(int[][] a) { if(DEBUG) for(int[] element : a) errprtln(element); } void errprtln(long[][] a) { if(DEBUG) for(long[] element : a) errprtln(element); } void errprtln(double[][] a) { if(DEBUG) for(double[] element : a) errprtln(element); } void errprtln(String[][] a) { if(DEBUG) for(String[] element : a) errprtln(element); } void errprtln(char[][] a) { if(DEBUG) for(char[] element : a) errprtln(element); } void errprtln(boolean[][] a) { if(DEBUG) for(boolean[] element : a) errprtln(element); } void errprtln(Object[][] a) { if(DEBUG) for(Object element : a) { errprtln(element); errprtln(); } } void reply(boolean b) { prtln(b ? "Yes" : "No"); } void REPLY(boolean b) { prtln(b ? "YES" : "NO"); } void flush() { out.flush(); if(DEBUG) err.flush(); } void assertion(boolean b) { if(!b) { flush(); throw new AssertionError(); } } void exit() { flush(); System.exit(0); } void exit(T a) { prtln(a); exit(); } void exit(int... a) { prtln(a); exit(); } void exit(long... a) { prtln(a); exit(); } void exit(double... a) { prtln(a); exit(); } void exit(String... a) { prtln(a); exit(); } void exit(char... a) { prtln(a); exit(); } void exit(boolean... a) { prtln(a); exit(); } void exit(int[][] a) { prtln(a); exit(); } void exit(long[][] a) { prtln(a); exit(); } void exit(double[][] a) { prtln(a); exit(); } void exit(String[][] a) { prtln(a); exit(); } void exit(char[][] a) { prtln(a); exit(); } void exit(boolean[][] a) { prtln(a); exit(); } final long INF = (long)1e18 + 7; boolean isPlusINF(long a) { return a > INF / 10; } boolean isMinusINF(long a) { return isPlusINF(- a); } boolean isINF(long a) { return isPlusINF(a) || isMinusINF(a); } final int I_INF = (int)1e9 + 7; boolean isPlusINF(int a) { return a > I_INF / 10; } boolean isMinusINF(int a) { return isPlusINF(- a); } boolean isINF(int a) { return isPlusINF(a) || isMinusINF(a); } int min(int a, int b) { return Math.min(a, b); } long min(long a, long b) { return Math.min(a, b); } double min(double a, double b) { return Math.min(a, b); } > T min(T a, T b) { return a.compareTo(b) <= 0 ? a : b; } int min(int... x) { int min = x[0]; for(int val : x) min = min(min, val); return min; } long min(long... x) { long min = x[0]; for(long val : x) min = min(min, val); return min; } double min(double... x) { double min = x[0]; for(double val : x) min = min(min, val); return min; } int max(int a, int b) { return Math.max(a, b); } long max(long a, long b) { return Math.max(a, b); } double max(double a, double b) { return Math.max(a, b); } > T max(T a, T b) { return a.compareTo(b) >= 0 ? a : b; } int max(int... x) { int max = x[0]; for(int val : x) max = max(max, val); return max; } long max(long... x) { long max = x[0]; for(long val : x) max = max(max, val); return max; } double max(double... x) { double max = x[0]; for(double val : x) max = max(max, val); return max; } > T max(T[] x) { T max = x[0]; for(T val : x) max = max(max, val); return max; } int max(int[][] a) { int max = a[0][0]; for(int[] ele : a) max = max(max, max(ele)); return max; } long max(long[][] a) { long max = a[0][0]; for(long[] ele : a) max = max(max, max(ele)); return max; } double max(double[][] a) { double max = a[0][0]; for(double[] ele : a) max = max(max, max(ele)); return max; } > T max(T[][] a) { T max = a[0][0]; for(T[] ele : a) max = max(max, max(ele)); return max; } long sum(int... a) { long sum = 0; for(int element : a) sum += element; return sum; } long sum(long... a) { long sum = 0; for(long element : a) sum += element; return sum; } double sum(double... a) { double sum = 0; for(double element : a) sum += element; return sum; } long sum(boolean... a) { long sum = 0; for(boolean element : a) sum += element ? 1 : 0; return sum; } long[] sums(int[] a) { long sum[] = new long[a.length + 1]; sum[0] = 0; for(int i = 0; i < a.length; i ++) sum[i + 1] = sum[i] + a[i]; return sum; } long[] sums(long[] a) { long sum[] = new long[a.length + 1]; sum[0] = 0; for(int i = 0; i < a.length; i ++) sum[i + 1] = sum[i] + a[i]; return sum; } double[] sums(double[] a) { double sum[] = new double[a.length + 1]; sum[0] = 0; for(int i = 0; i < a.length; i ++) sum[i + 1] = sum[i] + a[i]; return sum; } long[] sums(boolean[] a) { long sum[] = new long[a.length + 1]; sum[0] = 0; for(int i = 0; i < a.length; i ++) sum[i + 1] = sum[i] + (a[i] ? 1 : 0); return sum; } long[][] sums(int[][] a) { long sum[][] = new long[a.length + 1][a[0].length + 1]; fill(sum, 0); for(int i = 0; i < a.length; i ++) { for(int j = 0; j < a[i].length; j ++) { sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + a[i][j]; } } return sum; } long[][] sums(long[][] a) { long sum[][] = new long[a.length + 1][a[0].length + 1]; fill(sum, 0); for(int i = 0; i < a.length; i ++) { for(int j = 0; j < a[i].length; j ++) { sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + a[i][j]; } } return sum; } double[][] sums(double[][] a) { double sum[][] = new double[a.length + 1][a[0].length + 1]; fill(sum, 0); for(int i = 0; i < a.length; i ++) { for(int j = 0; j < a[i].length; j ++) { sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + a[i][j]; } } return sum; } long[][] sums(boolean[][] a) { long sum[][] = new long[a.length + 1][a[0].length + 1]; fill(sum, 0); for(int i = 0; i < a.length; i ++) { for(int j = 0; j < a[i].length; j ++) { sum[i + 1][j + 1] = sum[i + 1][j] + sum[i][j + 1] - sum[i][j] + (a[i][j] ? 1 : 0); } } return sum; } int constrain(int x, int l, int r) { return min(max(x, min(l, r)), max(l, r)); } long constrain(long x, long l, long r) { return min(max(x, min(l, r)), max(l, r)); } double constrain(double x, double l, double r) { return min(max(x, min(l, r)), max(l, r)); } int abs(int x) { return x >= 0 ? x : - x; } long abs(long x) { return x >= 0 ? x : - x; } double abs(double x) { return x >= 0 ? x : - x; } int signum(int x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } int signum(long x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } int signum(double x) { return x > 0 ? 1 : x < 0 ? -1 : 0; } long round(double x) { return Math.round(x); } long floor(double x) { return (long)Math.floor(x); } int divfloor(int a, int b) { return signum(a) == signum(b) ? a / b : - divceil(abs(a), abs(b)); } long divfloor(long a, long b) { return signum(a) == signum(b) ? a / b : - divceil(abs(a), abs(b)); } long ceil(double x) { return (long)Math.ceil(x); } int divceil(int a, int b) { return a >= 0 && b > 0 ? (a + b - 1) / b : a < 0 && b < 0 ? divceil(abs(a), abs(b)) : - divfloor(abs(a), abs(b)); } long divceil(long a, long b) { return a >= 0 && b > 0 ? (a + b - 1) / b : a < 0 && b < 0 ? divceil(abs(a), abs(b)) : - divfloor(abs(a), abs(b)); } double sqrt(int x) { return Math.sqrt((double)x); } double sqrt(long x) { return Math.sqrt((double)x); } double sqrt(double x) { return Math.sqrt(x); } long fact(int n) { long ans = 1; for(int i = 1; i <= n; i ++) ans = Math.multiplyExact(ans, i); return ans; } double pow(double x, double y) { return Math.pow(x, y); } long pow(long x, long y) { long ans = 1; while(true) { if(y % 2 != 0) ans = Math.multiplyExact(ans, x); y /= 2; if(y <= 0) return ans; x = Math.multiplyExact(x, x); } } int gcd(int a, int b) { while(true) { if(b == 0) return a; int tmp = a; a = b; b = tmp % b; } } long gcd(long a, long b) { while(true) { if(b == 0) return a; long tmp = a; a = b; b = tmp % b; } } long lcm(long a, long b) { return a / gcd(a, b) * b; } int gcd(int... a) { int gcd = 0; for(int i = 0; i < a.length; i ++) gcd = gcd(gcd, a[i]); return gcd; } long gcd(long... a) { long gcd = 0; for(int i = 0; i < a.length; i ++) gcd = gcd(gcd, a[i]); return gcd; } double random() { return Math.random(); } int random(int max) { return (int)floor(random() * max); } long random(long max) { return floor(random() * max); } double random(double max) { return random() * max; } int random(int min, int max) { return random(max - min) + min; } long random(long min, long max) { return random(max - min) + min; } double random(double min, double max) { return random(max - min) + min; } boolean isUpper(char a) { return a >= 'A' && a <= 'Z'; } boolean isLower(char a) { return a >= 'a' && a <= 'z'; } int upperToInt(char a) { return a - 'A'; } int lowerToInt(char a) { return a - 'a'; } int numToInt(char a) { return a - '0'; } int charToInt(char a) { return a >= 'a' ? lowerToInt(a) : a >= 'A' ? upperToInt(a) : numToInt(a); } char intToUpper(int a) { return (char)(a + 'A'); } char intToLower(int a) { return (char)(a + 'a'); } char intToNum(int a) { return (char)(a + '0'); } int[] charToInt(char[] a) { int array[] = new int[a.length]; for(int i = 0; i < a.length; i ++) array[i] = charToInt(a[i]); return array; } int numDigits(long a) { return Long.toString(a).length(); } long bitFlag(int a) { return 1L << (long)a; } boolean isFlagged(long x, int a) { return (x & bitFlag(a)) != 0; } long countString(String str, String a) { return (str.length() - str.replace(a, "").length()) / a.length(); } long countStringAll(String str, String a) { return str.length() - str.replaceAll(a, "").length(); } void fill(int[] array, int x) { Arrays.fill(array, x); } void fill(long[] array, long x) { Arrays.fill(array, x); } void fill(double[] array, double x) { Arrays.fill(array, x); } void fill(char[] array, char x) { Arrays.fill(array, x); } void fill(boolean[] array, boolean x) { Arrays.fill(array, x); } void fill(int[][] array, int x) { for(int[] a : array) fill(a, x); } void fill(long[][] array, long x) { for(long[] a : array) fill(a, x); } void fill(double[][] array, double x) { for(double[] a : array) fill(a, x); } void fill(char[][] array, char x) { for(char[] a : array) fill(a, x); } void fill(boolean[][] array, boolean x) { for(boolean[] a : array) fill(a, x); } void fill(int[][][] array, int x) { for(int[][] a : array) fill(a, x); } void fill(long[][][] array, long x) { for(long[][] a : array) fill(a, x); } void fill(double[][][] array, double x) { for(double[][] a : array) fill(a, x); } void fill(char[][][] array, char x) { for(char[][] a : array) fill(a, x); } void fill(boolean[][][] array, boolean x) { for(boolean[][] a : array) fill(a, x); } // graph class Graph { int numNode; int numEdge; boolean directed; Set edges = new HashSet<>(); Node nodes[]; Node reversedNodes[]; Graph(int numNode, int numEdge, boolean directed) { this.numNode = numNode; this.numEdge = numEdge; this.directed = directed; nodes = new Node[numNode]; reversedNodes = new Node[numNode]; for(int i = 0; i < numNode; i ++) { nodes[i] = new Node(i); reversedNodes[i] = new Node(i); } } void init(Set edges) { this.edges = edges; for(Edge e : edges) add(e); } void add(Edge e) { edges.add(e); nodes[e.source].add(e.target, e.cost); if(directed) reversedNodes[e.target].add(e.source, e.cost); else nodes[e.target].add(e.source, e.cost); } void remove(Edge e) { edges.remove(e); nodes[e.source].remove(e.target, e.cost); if(directed) reversedNodes[e.target].remove(e.source, e.cost); else nodes[e.target].remove(e.source, e.cost); } void update(Edge e, long cost) { nodes[e.source].update(e.target, cost); if(directed) reversedNodes[e.target].update(e.source, cost); else nodes[e.target].update(e.source, cost); e.cost = cost; } void update(int source, int target, long cost) { update(new Edge(source, target, cost), cost); } void clearNodes() { for(Node n : nodes) n.clear(); for(Node n : reversedNodes) n.clear(); } } class Node extends HashSet { int id; Node(int id) { this.id = id; } void add(int target, long cost) { add(new Edge(id, target, cost)); } void remove(int target, long cost) { remove(new Edge(id, target, cost)); } void update(int target, long cost) { remove(target, cost); add(target, cost); } } class Edge implements Comparable { int source; int target; long cost; Edge(int source, int target, long cost) { this.source = source; this.target = target; this.cost = cost; } @Override public String toString() { return source+" - "+cost+" -> "+target; } @Override public int hashCode() { return Objects.hash(source, target); } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(this.getClass() != obj.getClass()) return false; Edge that = (Edge) obj; if(this.source != that.source) return false; if(this.target != that.target) return false; return true; } @Override public int compareTo(Edge that) { int c = Long.compare(this.cost, that.cost); if(c == 0) c = Integer.compare(this.source, that.source); if(c == 0) c = Integer.compare(this.target, that.target); return c; } } class PairLL implements Comparable { long a; long b; PairLL() { } PairLL(long a, long b) { this.a = a; this.b = b; } @Override public String toString() { return "("+a+", "+b+")"; } @Override public int hashCode() { return Objects.hash(a, b); } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null) return false; if(this.getClass() != obj.getClass()) return false; PairLL that = (PairLL) obj; if(this.a != that.a || this.b != that.b) return false; return true; } @Override public int compareTo(PairLL that) { int c = Long.compare(this.a, that.a); if(c == 0) c = Long.compare(this.b, that.b); return c; } } class TupleLLL implements Comparable { long a; long b; long c; TupleLLL() { } TupleLLL(long a, long b, long c) { this.a = a; this.b = b; this.c = c; } @Override public String toString() { return "("+a+", "+b+", "+c+")"; } @Override public int hashCode() { return Objects.hash(a, b, c); } @Override public boolean equals(Object obj) { if(this == obj) return true; if(obj == null || this.getClass() != obj.getClass()) return false; TupleLLL that = (TupleLLL) obj; if(this.a != that.a || this.b != that.b || this.c != that.c) return false; return true; } @Override public int compareTo(TupleLLL that) { int c = Long.compare(this.a, that.a); if(c == 0) c = Long.compare(this.b, that.b); if(c == 0) c = Long.compare(this.c, that.c); return c; } } PairLL npll() { return new PairLL(nl(), nl()); } PairLL[] npll(int n) { PairLL a[] = new PairLL[n]; for(int i = 0; i < n; i ++) a[i] = npll(); return a; } // mods long mod(long x, long mod) { x %= mod; return x + (x < 0 ? mod : 0); } // O(1) long pow_m(long x, long y, long mod) { // (logY) x = mod(x, mod); long ans = 1; for(; y > 0; y /= 2) { if(y % 2 != 0) ans = mod(ans * x, mod); x = mod(x * x, mod); } return ans; } long inv(long x, long mod) { return pow_m(x, mod - 2, mod); } // O(logM) final long MOD = (long)1e9 + 7; // 998244353; long mod(long x) { return mod(x, MOD); } void mod(long[] a) { for(int i = 0; i < a.length; i ++) a[i] = mod(a[i]); } void mod(long[][] a) { for(int i = 0; i < a.length; i ++) mod(a[i]); } void mod(long[][][] a) { for(int i = 0; i < a.length; i ++) mod(a[i]); } public void solve() { PairLL ans = chineseRem(npll(3)); prtln(ans == null ? -1 : ans.a == 0 ? ans.b : ans.a); } // return (g,x) s.t. ax%mod=g=gcd(a,mod) && x>=0 PairLL invGcd(long a, long mod) { // O(loglcm(a,mod)) PairLL s = new PairLL(mod, 0); PairLL t = new PairLL(a, 1); while(t.a > 0) { long tmp = s.a / t.a; PairLL u = new PairLL(s.a - t.a * tmp, s.b - t.b * tmp); s = t; t = u; } if(s.b < 0) s.b += mod / s.a; return s; } // return (g,x,y) s.t. ax+by=g=gcd(a,b) && |x|+|y| is minimal (primarily) && x<=y (secondarily) TupleLLL extGcd(long a, long b) { // O(loglcm(a,b)) TupleLLL s = new TupleLLL(a, 1, 0); TupleLLL t = new TupleLLL(b, 0, 1); while(t.a > 0) { long tmp = s.a / t.a; TupleLLL u = new TupleLLL(s.a - t.a * tmp, s.b - t.b * tmp, s.c - t.c * tmp); s = t; t = u; } return s; } // return (x, lcm(ps.b)) s.t. x%ps.b=ps.a && x>=0 if exists otherwise (0,0) PairLL chineseRem(PairLL[] ps) { // O(Nloglcm(ps.a)) int num = ps.length; PairLL ans = new PairLL(0, 1); for(PairLL p : ps) { ans = chineseRem(ans, p); if(ans == null) return ans; } return ans; } // return (x,lcm(p1.b,p2.b)) s.t. x%p1.b=p1.a && x%p2.b=p2.a && x>=0 if exists otherwise (0,0) PairLL chineseRem(PairLL p1, PairLL p2) { // O(loglcm(p1.a,p2.a)) TupleLLL ans = extGcd(p1.b, p2.b); if((p2.a - p1.a) % ans.a != 0) return null; long lcm = p1.b / ans.a * p2.b; long tmp = (p2.a - p1.a) / ans.a * ans.b % (p2.b / ans.a); long r = (p1.a + p1.b * tmp) % lcm; if(r < 0) r += lcm; return new PairLL(r, lcm); } // return x%mod s.t. x%p.b=p.a && x>=0 if exists otherwise (0,0) long garner(PairLL[] p, long mod) { // O(N^2+Nlogmax(p.a))) PairLL p2[] = new PairLL[p.length + 1]; for(int i = 0; i < p.length; i ++) p2[i] = p[i]; p = p2; p[p.length - 1] = new PairLL(mod, 0); long coffs[] = new long[p.length]; fill(coffs, 1); long constants[] = new long[p.length]; fill(constants, 0); for(int i = 0; i < p.length - 1; i ++) { long v = (p[i].b - constants[i]) * inv(coffs[i], p[i].a) % p[i].a; if(v < 0) v += p[i].a; for(int j = i + 1; j < p.length; j++) { constants[j] += coffs[j] * v; constants[j] %= p[j].a; coffs[j] *= p[i].a; coffs[j] %= p[j].a; } } return constants[p.length - 1]; } } }