fn main() { input! { t: usize, ask: [(usize, usize, i64, i64, i64, i64); t], } if t <= 5 { solve::<21, 11>(ask); } else { solve::<5, 3>(ask); } } fn solve(ask: Vec<(usize, usize, i64, i64, i64, i64)>) { let pc = Precalc::new(100); for (p, q, n, m, a, b) in ask { let c = a.div_euclid(m); let a = a - c * m; let d = b.div_euclid(m); let b = b - d * m; let res = under_fold( n as usize + 1, m as usize, a as usize, b as usize, FloorSum::::dx(), FloorSum::::dy(), ) .flush(); let c = M::from(c); let d = M::from(d); let mut ans = M::zero(); for i in 0..=q { for j in 0..=(q - i) { let k = q - i - j; let mut v = res[p + j][i]; v *= c.pow(j as u64) * d.pow(k as u64); v *= pc.fact(q) * pc.ifact(i) * pc.ifact(j) * pc.ifact(k); ans += v; } } println!("{}", ans); } } type M = ModInt<998_244_353>; #[derive(Clone)] pub struct FloorSum { x: [T; A], y: [T; B], sum: [[T; B]; A], id: bool, } impl FloorSum where T: Ring + Copy, { fn dx() -> Self { let mut res = Self::id(); let u = A.min(2); res.x[..u].fill(T::one()); res.y[0] = T::one(); res.sum[0][0] = T::one(); res.id = false; res } fn dy() -> Self { let mut res = Self::id(); let u = B.min(2); res.y[..u].fill(T::one()); res.x[0] = T::one(); res.id = false; res } fn flush(&self) -> [[T; B]; A] { let coef = FloorPow::::precalc(); let mut sum = self.sum; for s in sum.iter_mut() { let mut t = [T::zero(); B]; for (t, c) in t.iter_mut().zip(coef.iter()) { for (s, c) in s.iter().zip(c.iter()) { *t = *t + *c * *s; } } *s = t; } let mut sum = transpose(sum); let coef = FloorPow::::precalc(); for s in sum.iter_mut() { let mut t = [T::zero(); A]; for (t, c) in t.iter_mut().zip(coef.iter()) { for (s, c) in s.iter().zip(c.iter()) { *t = *t + *c * *s; } } *s = t; } transpose(sum) } } impl Monoid for FloorSum where T: Ring + Copy, { fn id() -> Self { Self { x: [T::zero(); A], y: [T::zero(); B], sum: [[T::zero(); B]; A], id: true, } } fn merge(&self, rhs: &Self) -> Self { if self.id { return rhs.clone(); } if rhs.id { return self.clone(); } let mut res = Self::id(); res.id = false; for (i, a) in self.x.iter().enumerate() { for (x, b) in res.x[i..].iter_mut().zip(rhs.x.iter()) { *x = *x + *a * *b; } } for (i, a) in self.y.iter().enumerate() { for (x, b) in res.y[i..].iter_mut().zip(rhs.y.iter()) { *x = *x + *a * *b; } } for (i, a) in self.x.iter().enumerate() { for (res, b) in res.sum[i..].iter_mut().zip(rhs.sum.iter()) { for (res, b) in res.iter_mut().zip(b.iter()) { *res = *res + *a * *b; } } } for res in res.sum.iter_mut() { let mut next = [T::zero(); B]; for (j, b) in self.y.iter().enumerate() { for (next, res) in next[j..].iter_mut().zip(res.iter()) { *next = *next + *res * *b; } } *res = next; } for (res, a) in res.sum.iter_mut().zip(self.sum.iter()) { for (res, a) in res.iter_mut().zip(a.iter()) { *res = *res + *a; } } res } } pub trait Monoid: Clone { fn id() -> Self; fn merge(&self, rhs: &Self) -> Self; fn pow(&self, mut n: usize) -> Self { let mut t = Self::id(); let mut r = self.clone(); while n > 0 { if n & 1 == 1 { t = t.merge(&r); } r = r.merge(&r); n >>= 1; } t } } pub fn under_fold( mut n: usize, mut m: usize, mut a: usize, mut b: usize, mut x: T, mut y: T, ) -> T where T: Monoid, { let mut front = T::id(); let mut tail = T::id(); let mut c = (a * n + b) / m; loop { if a >= m { let q = a / m; a %= m; x = x.merge(&y.pow(q)); c -= q * n; } if b >= m { let q = b / m; b %= m; front = front.merge(&y.pow(q)); c -= q; } if c == 0 { break; } let need = (m * c - b + a - 1) / a; tail = y.merge(&x.pow(n - need)).merge(&tail); n = c - 1; c = need; b = m - b + a - 1; std::mem::swap(&mut a, &mut m); std::mem::swap(&mut x, &mut y); } front.merge(&x.pow(n)).merge(&tail) } #[derive(Clone)] pub struct FloorPow { y: [T; N], s: [T; N], } impl Monoid for FloorPow where T: Ring + Copy, { fn id() -> Self { let mut y = [T::zero(); N]; y[0] = T::one(); Self { y, s: [T::zero(); N], } } fn merge(&self, rhs: &Self) -> Self { let mut y = [T::zero(); N]; for (i, a) in self.y.iter().enumerate() { for (y, b) in y[i..].iter_mut().zip(rhs.y.iter()) { *y = *y + *a * *b; } } let mut s = self.s; for (i, a) in self.y.iter().enumerate() { for (s, b) in s[i..].iter_mut().zip(rhs.s.iter()) { *s = *s + *a * *b; } } Self { y, s } } } impl FloorPow where T: Ring + Copy, { pub fn dx() -> Self { let mut res = Self::id(); res.s[0] = T::one(); res } pub fn dy() -> Self { assert!(N >= 2); let mut res = Self::id(); res.y[1] = T::one(); res } pub fn flush(&self) -> [T; N] { let coef = Self::precalc(); let mut res = [T::zero(); N]; for (res, coef) in res.iter_mut().zip(coef.iter()) { for (s, c) in self.s.iter().zip(coef.iter()) { *res = *res + *c * *s; } } res } fn precalc() -> [[T; N]; N] { let mut binom = [[T::zero(); N]; N]; binom[0][0] = T::one(); for i in 1..N { binom[i][0] = T::one(); for j in 1..(i + 1) { binom[i][j] = binom[i - 1][j - 1] + binom[i - 1][j]; } } let mut pow = [[T::zero(); N]; N]; let mut r = T::zero(); for i in 1..N { r = r + T::one(); pow[i][0] = T::one(); for j in 1..N { pow[i][j] = pow[i][j - 1] * r; } } let mut coef = [[T::zero(); N]; N]; for k in 1..N { for i in 1..(k + 1) { let mut c = T::zero(); for j in 1..(i + 1) { let v = binom[i][j] * pow[j][k]; if (i - j) % 2 == 0 { c = c + v; } else { c = c - v; } } coef[k][i] = c; } } coef[0][0] = T::one(); coef } } pub fn transpose(a: [[T; B]; A]) -> [[T; A]; B] where T: Copy, { let mut res = [[a[0][0]; A]; B]; for (i, a) in a.iter().enumerate() { for (res, a) in res.iter_mut().zip(a.iter()) { res[i] = *a; } } res } // ---------- 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 ---------- use std::ops::*; // ---------- begin trait ---------- pub trait Zero: Sized + Add { fn zero() -> Self; fn is_zero(&self) -> bool; } pub trait One: Sized + Mul { fn one() -> Self; fn is_one(&self) -> bool; } pub trait SemiRing: Zero + One {} pub trait Ring: SemiRing + Sub + Neg {} pub trait Field: Ring + Div {} impl SemiRing for T where T: Zero + One {} impl Ring for T where T: SemiRing + Sub + Neg {} impl Field for T where T: Ring + Div {} // ---------- end trait ---------- // ---------- begin modint ---------- pub const fn pow_mod(mut r: u32, mut n: u32, m: u32) -> u32 { let mut t = 1; while n > 0 { if n & 1 == 1 { t = (t as u64 * r as u64 % m as u64) as u32; } r = (r as u64 * r as u64 % m as u64) as u32; n >>= 1; } t } pub const fn primitive_root(p: u32) -> u32 { let mut m = p - 1; let mut f = [1; 30]; let mut k = 0; let mut d = 2; while d * d <= m { if m % d == 0 { f[k] = d; k += 1; } while m % d == 0 { m /= d; } d += 1; } if m > 1 { f[k] = m; k += 1; } let mut g = 1; while g < p { let mut ok = true; let mut i = 0; while i < k { ok &= pow_mod(g, (p - 1) / f[i], p) > 1; i += 1; } if ok { break; } g += 1; } g } pub const fn is_prime(n: u32) -> bool { if n <= 1 { return false; } let mut d = 2; while d * d <= n { if n % d == 0 { return false; } d += 1; } true } #[derive(Clone, Copy, PartialEq, Eq)] pub struct ModInt(u32); impl ModInt<{ M }> { const REM: u32 = { let mut t = 1u32; let mut s = !M + 1; let mut n = !0u32 >> 2; while n > 0 { if n & 1 == 1 { t = t.wrapping_mul(s); } s = s.wrapping_mul(s); n >>= 1; } t }; const INI: u64 = ((1u128 << 64) % M as u128) as u64; const IS_PRIME: () = assert!(is_prime(M)); const PRIMITIVE_ROOT: u32 = primitive_root(M); const ORDER: usize = 1 << (M - 1).trailing_zeros(); const fn reduce(x: u64) -> u32 { let _ = Self::IS_PRIME; let b = (x as u32 * Self::REM) as u64; let t = x + b * M as u64; let mut c = (t >> 32) as u32; if c >= M { c -= M; } c as u32 } const fn multiply(a: u32, b: u32) -> u32 { Self::reduce(a as u64 * b as u64) } pub const fn new(v: u32) -> Self { assert!(v < M); Self(Self::reduce(v as u64 * Self::INI)) } pub const fn const_mul(&self, rhs: Self) -> Self { Self(Self::multiply(self.0, rhs.0)) } pub const fn pow(&self, mut n: u64) -> Self { let mut t = Self::new(1); let mut r = *self; while n > 0 { if n & 1 == 1 { t = t.const_mul(r); } r = r.const_mul(r); n >>= 1; } t } pub const fn inv(&self) -> Self { assert!(self.0 != 0); self.pow(M as u64 - 2) } pub const fn get(&self) -> u32 { Self::reduce(self.0 as u64) } pub const fn zero() -> Self { Self::new(0) } pub const fn one() -> Self { Self::new(1) } } impl Add for ModInt<{ M }> { type Output = Self; fn add(self, rhs: Self) -> Self::Output { let mut v = self.0 + rhs.0; if v >= M { v -= M; } Self(v) } } impl Sub for ModInt<{ M }> { type Output = Self; fn sub(self, rhs: Self) -> Self::Output { let mut v = self.0 - rhs.0; if self.0 < rhs.0 { v += M; } Self(v) } } impl Mul for ModInt<{ M }> { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { self.const_mul(rhs) } } impl Div for ModInt<{ M }> { type Output = Self; fn div(self, rhs: Self) -> Self::Output { self * rhs.inv() } } impl AddAssign for ModInt<{ M }> { fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } } impl SubAssign for ModInt<{ M }> { fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } } impl MulAssign for ModInt<{ M }> { fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } impl DivAssign for ModInt<{ M }> { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } } impl Neg for ModInt<{ M }> { type Output = Self; fn neg(self) -> Self::Output { if self.0 == 0 { self } else { Self(M - self.0) } } } impl std::fmt::Display for ModInt<{ M }> { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { write!(f, "{}", self.get()) } } impl std::fmt::Debug for ModInt<{ M }> { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { write!(f, "{}", self.get()) } } impl std::str::FromStr for ModInt<{ M }> { type Err = std::num::ParseIntError; fn from_str(s: &str) -> Result { let val = s.parse::()?; Ok(ModInt::new(val)) } } impl From for ModInt<{ M }> { fn from(val: usize) -> ModInt<{ M }> { ModInt::new((val % M as usize) as u32) } } impl From for ModInt<{ M }> { fn from(val: i64) -> ModInt<{ M }> { ModInt::new((val % M as i64 + M as i64) as u32 % M) } } // ---------- end modint ---------- // ---------- begin precalc ---------- pub struct Precalc { fact: Vec>, ifact: Vec>, inv: Vec>, } impl Precalc { pub fn new(size: usize) -> Self { let mut fact = vec![ModInt::one(); size + 1]; let mut ifact = vec![ModInt::one(); size + 1]; let mut inv = vec![ModInt::one(); size + 1]; for i in 2..=size { fact[i] = fact[i - 1] * ModInt::from(i); } ifact[size] = fact[size].inv(); for i in (2..=size).rev() { inv[i] = ifact[i] * fact[i - 1]; ifact[i - 1] = ifact[i] * ModInt::from(i); } Self { fact, ifact, inv } } pub fn fact(&self, n: usize) -> ModInt { self.fact[n] } pub fn ifact(&self, n: usize) -> ModInt { self.ifact[n] } pub fn inv(&self, n: usize) -> ModInt { assert!(0 < n); self.inv[n] } pub fn perm(&self, n: usize, k: usize) -> ModInt { if k > n { return ModInt::zero(); } self.fact[n] * self.ifact[n - k] } pub fn binom(&self, n: usize, k: usize) -> ModInt { if n < k { return ModInt::zero(); } self.fact[n] * self.ifact[k] * self.ifact[n - k] } } // ---------- end precalc ---------- impl Zero for ModInt<{ M }> { fn zero() -> Self { Self::zero() } fn is_zero(&self) -> bool { self.0 == 0 } } impl One for ModInt<{ M }> { fn one() -> Self { Self::one() } fn is_one(&self) -> bool { self.get() == 1 } }