fn main() { input! { n: usize, p: [(i64, i64); n], } let mut solver = Garner::new(); for (r, m) in p { solver.push(m, r); } const MOD: i64 = 1_000_000_007; let mut ans = solver.find(MOD).unwrap_or(-1); if solver.digit.iter().all(|p| *p == 0) { ans = solver.base.iter().fold(0, |s, a| s * *a % MOD); } println!("{}", ans); } // X = sum_{0<=i} digit[i] * prod_{j, digit: Vec, } impl Garner { pub fn new() -> Self { Self { base: vec![], digit: vec![], } } // X = r (mod m) // という条件の追加 pub fn push(&mut self, m: i64, r: i64) { assert!(0 <= r && r < m && m < (1i64 << 31)); if self.base.last().map_or(false, |p| *p <= 0) { self.base.push(-1); self.digit.push(-1); return; } let mut a = 0; let mut b = 1; for (base, digit) in self.base.iter().zip(self.digit.iter()) { a = (a + *digit * b) % m; b = b * *base % m; } let r = (r - a).rem_euclid(m); let (p, _, g) = calc(b, m); if r % g != 0 { self.base.push(-1); self.digit.push(-1); } else { let m = m / g; self.base.push(m); self.digit.push((p * (r / g)).rem_euclid(m)); } } pub fn pop(&mut self) { self.base.pop(); self.digit.pop(); } // X mod m pub fn find(&self, m: i64) -> Option { assert!(0 < m && m < (1i64 << 31)); if self.base.last().map_or(false, |p| *p <= 0) { return None; } let mut s = 0; for (base, digit) in self.base.iter().zip(self.digit.iter()).rev() { s = (s * *base + *digit) % m; } Some(s) } } // return (a, b, g) // g = gcd(x, y) // ax + by = gcd(x, y) fn calc(x: i64, y: i64) -> (i64, i64, i64) { if y == 0 { return (x.signum(), 0, x.abs()); } let q = x.div_euclid(y); let r = x.rem_euclid(y); let p = calc(y, r); (p.1, p.0 - q * p.1, p.2) } // ---------- begin input macro ---------- // reference: https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 #[macro_export] macro_rules! input { (source = $s:expr, $($r:tt)*) => { let mut iter = $s.split_whitespace(); input_inner!{iter, $($r)*} }; ($($r:tt)*) => { let s = { use std::io::Read; let mut s = String::new(); std::io::stdin().read_to_string(&mut s).unwrap(); s }; let mut iter = s.split_whitespace(); input_inner!{iter, $($r)*} }; } #[macro_export] macro_rules! input_inner { ($iter:expr) => {}; ($iter:expr, ) => {}; ($iter:expr, $var:ident : $t:tt $($r:tt)*) => { let $var = read_value!($iter, $t); input_inner!{$iter $($r)*} }; } #[macro_export] macro_rules! read_value { ($iter:expr, ( $($t:tt),* )) => { ( $(read_value!($iter, $t)),* ) }; ($iter:expr, [ $t:tt ; $len:expr ]) => { (0..$len).map(|_| read_value!($iter, $t)).collect::>() }; ($iter:expr, chars) => { read_value!($iter, String).chars().collect::>() }; ($iter:expr, bytes) => { read_value!($iter, String).bytes().collect::>() }; ($iter:expr, usize1) => { read_value!($iter, usize) - 1 }; ($iter:expr, $t:ty) => { $iter.next().unwrap().parse::<$t>().expect("Parse error") }; } // ---------- end input macro ----------