結果
問題 |
No.3250 最小公倍数
|
ユーザー |
![]() |
提出日時 | 2025-09-06 19:37:07 |
言語 | Rust (1.83.0 + proconio) |
結果 |
AC
|
実行時間 | 882 ms / 2,000 ms |
コード長 | 32,512 bytes |
コンパイル時間 | 15,922 ms |
コンパイル使用メモリ | 380,044 KB |
実行使用メモリ | 208,636 KB |
最終ジャッジ日時 | 2025-09-06 19:37:36 |
合計ジャッジ時間 | 28,042 ms |
ジャッジサーバーID (参考情報) |
judge2 / judge |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 1 |
other | AC * 21 |
ソースコード
use std::io::Write; type M = ModInt<998244353>; fn run() { input! { n: usize, a: [usize; n], e: [(usize1, usize1); n - 1], } let g = CSR::new(n, e.into_iter().flat_map(|e| [e, (e.1, e.0)])); let m = *a.iter().max().unwrap(); let sieve = Sieve::new(m); let mut range = vec![(2 * n, 0); n]; let mut depth = vec![0; n]; let mut memo = vec![]; let mut dfs = vec![(0, n, g.list(0))]; while let Some((v, p, mut lst)) = dfs.pop() { range[v].0.chmin(memo.len()); range[v].1.chmax(memo.len()); memo.push((depth[v], v as u32)); if let Some(u) = lst.find(|u| *u != p) { depth[u] = depth[v] + 1; dfs.push((v, p, lst)); dfs.push((u, v, g.list(u))); } } let table = SparseTable::new(memo, |a, b| std::cmp::min(*a, *b)); let lca = |x: usize, y: usize| -> usize { let p = range[x]; let q = range[y]; table.find(p.0.min(q.0), p.1.max(q.1) + 1).1 as usize }; let last = std::cell::RefCell::new(vec![n; m + 1]); let ans = std::cell::RefCell::new(a.iter().map(|a| M::from(*a)).collect::<Vec<_>>()); let pc = Precalc::new(m); recurse(|rec, (v, p): (usize, usize)| { let mut val = a[v]; while let Some(p) = sieve.factor(val) { let mut pow = 1; while val % p == 0 { val /= p; pow *= p; let u = last.borrow()[pow]; if u != n { ans.borrow_mut()[lca(u, v)] *= pc.inv(p); } last.borrow_mut()[pow] = v; } } for u in g.list(v).filter(|u| *u != p) { rec((u, v)); let c = ans.borrow()[u]; ans.borrow_mut()[v] *= c; } })((0, n)); let out = std::io::stdout(); let mut out = std::io::BufWriter::new(out.lock()); for a in ans.into_inner() { writeln!(out, "{}", a).ok(); } } fn main() { run(); } // ---------- 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::<Vec<_>>() }; ($iter:expr, chars) => { read_value!($iter, String).chars().collect::<Vec<char>>() }; ($iter:expr, bytes) => { read_value!($iter, String).bytes().collect::<Vec<u8>>() }; ($iter:expr, usize1) => { read_value!($iter, usize) - 1 }; ($iter:expr, $t:ty) => { $iter.next().unwrap().parse::<$t>().expect("Parse error") }; } // ---------- end input macro ---------- // ---------- begin Heavy-Light decomposition ---------- pub struct HLD { size: usize, edge: Vec<(usize, usize)>, child: Vec<Vec<usize>>, path_root: Vec<usize>, parent: Vec<usize>, left: Vec<usize>, right: Vec<usize>, inverse: Vec<usize>, } impl HLD { pub fn new(size: usize) -> Self { assert!(size <= 10usize.pow(8)); HLD { size: size, edge: Vec::with_capacity(size - 1), child: Vec::new(), path_root: Vec::new(), parent: Vec::new(), left: Vec::new(), right: Vec::new(), inverse: Vec::new(), } } pub fn add_edge(&mut self, a: usize, b: usize) { assert!(a != b && a < self.size && b < self.size); self.edge.push((a, b)); } pub fn build(&mut self, root: usize) { assert!(self.edge.len() + 1 == self.size); let size = self.size; let mut cnt = vec![0; size]; for &(a, b) in self.edge.iter() { cnt[a] += 1; cnt[b] += 1; } let mut child = cnt .into_iter() .map(|c| Vec::with_capacity(c)) .collect::<Vec<_>>(); for &(a, b) in self.edge.iter() { child[a].push(b); child[b].push(a); } let mut parent = vec![size; size]; let mut q = Vec::with_capacity(size); q.push(root); parent[root] = root; for i in 0..size { let v = q[i]; for u in child[v].clone() { assert!(parent[u] == size); parent[u] = v; child[u].retain(|e| *e != v); q.push(u); } } let mut sum = vec![1; size]; for &v in q.iter().rev() { let child = &mut child[v]; if !child.is_empty() { let (pos, _) = child.iter().enumerate().max_by_key(|p| sum[*p.1]).unwrap(); child.swap(0, pos); sum[v] = 1 + child.iter().fold(0, |s, a| s + sum[*a]); } } let mut path_root = (0..size).collect::<Vec<_>>(); let mut left = vec![0; size]; let mut right = vec![0; size]; let mut dfs = vec![(root, false)]; let mut id = 0; while let Some((v, end)) = dfs.pop() { if end { right[v] = id; continue; } left[v] = id; id += 1; dfs.push((v, true)); let child = &child[v]; if !child.is_empty() { for &u in child[1..].iter() { path_root[u] = u; dfs.push((u, false)); } let u = child[0]; path_root[u] = path_root[v]; dfs.push((u, false)); } } let mut inverse = vec![size; size]; for (i, l) in left.iter().enumerate() { inverse[*l] = i; } self.child = child; self.parent = parent; self.left = left; self.right = right; self.path_root = path_root; self.inverse = inverse; } pub fn lca(&self, mut a: usize, mut b: usize) -> usize { assert!(a < self.size && b < self.size); let path = &self.path_root; let parent = &self.parent; let index = &self.left; while path[a] != path[b] { if index[a] > index[b] { std::mem::swap(&mut a, &mut b); } b = parent[path[b]]; } std::cmp::min((index[a], a), (index[b], b)).1 } pub fn path( &self, src: usize, dst: usize, up: &mut Vec<(usize, usize)>, down: &mut Vec<(usize, usize)>, ) { assert!(src < self.size && dst < self.size); up.clear(); down.clear(); let path = &self.path_root; let parent = &self.parent; let index = &self.left; let mut x = src; let mut y = dst; while path[x] != path[y] { if index[x] > index[y] { let p = path[x]; assert!(p == path[p]); up.push((index[p], index[x] + 1)); x = parent[p]; } else { let p = path[y]; assert!(p == path[p]); down.push((index[p], index[y] + 1)); y = parent[p]; } } if index[x] <= index[y] { down.push((index[x], index[y] + 1)); } else { up.push((index[y], index[x] + 1)); } down.reverse(); } pub fn sub_tree(&self, v: usize) -> (usize, usize) { assert!(v < self.size); (self.left[v], self.right[v]) } pub fn parent(&self, v: usize) -> Option<usize> { assert!(v < self.size); let p = self.parent[v]; if p == v { None } else { Some(p) } } // s -> t へのパスの2番目の頂点を返す pub fn next(&self, s: usize, t: usize) -> usize { assert!(s < self.size && t < self.size && s != t); let (a, b) = self.sub_tree(s); let (c, d) = self.sub_tree(t); if !(a <= c && d <= b) { return self.parent[s]; } let mut pos = t; let mut pre = t; while self.path_root[s] != self.path_root[pos] { pre = self.path_root[pos]; pos = self.parent[pre]; } if s == pos { pre } else { self.child[s][0] } } pub fn vertex(&self, x: usize) -> usize { assert!(x < self.size); self.inverse[x] } pub fn jump(&self, s: usize, t: usize, mut k: usize, up: &mut Vec<(usize, usize)>, down: &mut Vec<(usize, usize)>) -> Option<usize> { assert!(s.max(t) < self.size); self.path(s, t, up, down); for (l, r) in up.drain(..) { if k < r - l { return Some(self.vertex(r - 1 - k)); } k -= r - l; } for (l, r) in down.drain(..) { if k < r - l { return Some(self.vertex(l + k)); } k -= r - l; } None } } // ---------- end Heavy-Light decomposition ---------- // ---------- begin init array ---------- // 初期化配列 // 初期値とサイズを与えて適当にやる系 // new(size, zero): zero埋めした長さsizeの配列を返す // init(&mut self): 初期化 // init_with(&mut self, f): 非zero な添字とその値をfに渡して初期化 // indexMut でアクセスしたときその履歴を溜め込む // それ以外でアクセスすると死ぬので注意 // // 考えるべきこと // 1. deref で dataへアクセスできるようにしていいか // derefmut はダメ // 2. 今のままだと二次元配列の初期化とかには対応できない // なんか方法を考えたい #[derive(Clone)] pub struct InitArray<T> { data: Vec<T>, used: Vec<bool>, list: Vec<u32>, zero: T, } impl<T: Copy> InitArray<T> { pub fn new(zero: T, size: usize) -> Self { InitArray { data: vec![zero; size], used: vec![false; size], list: vec![], zero: zero, } } pub fn init(&mut self) { self.init_with(|_, _| ()); } pub fn init_with<F>(&mut self, mut f: F) where F: FnMut(usize, T), { for x in self.list.drain(..) { let x = x as usize; self.used[x] = false; let v = std::mem::replace(&mut self.data[x], self.zero); f(x, v); } } } impl<T> std::ops::Index<usize> for InitArray<T> { type Output = T; fn index(&self, pos: usize) -> &Self::Output { &self.data[pos] } } impl<T> std::ops::IndexMut<usize> for InitArray<T> { fn index_mut(&mut self, pos: usize) -> &mut Self::Output { if !self.used[pos] { self.used[pos] = true; self.list.push(pos as u32); } &mut self.data[pos] } } // ---------- end init array ---------- // --------- end sieve ---------- pub struct Sieve { size: usize, factor: Vec<usize>, } impl Sieve { pub fn new(size: usize) -> Sieve { let mut factor = (0..(size + 1)).collect::<Vec<_>>(); for i in (2..).take_while(|p| p * p <= size) { if i == factor[i] { for j in i..(size / i + 1) { factor[j * i] = i; } } } Sieve { size: size, factor: factor, } } pub fn factor(&self, n: usize) -> Option<usize> { assert!(n <= self.size); if n == 1 { None } else { Some(self.factor[n]) } } pub fn factorize(&self, mut n: usize, res: &mut Vec<usize>) { assert!(n <= self.size); res.clear(); res.push(1); while let Some(p) = self.factor(n) { let len = res.len(); while n % p == 0 { n /= p; for _ in 0..len { let v = res[res.len() - len] * p; res.push(v); } } } } } // --------- end sieve ---------- // ---------- begin recurse ---------- // reference // https://twitter.com/noshi91/status/1393952665566994434 // https://twitter.com/shino16_cp/status/1393933468082397190 pub fn recurse<A, R, F>(f: F) -> impl Fn(A) -> R where F: Fn(&dyn Fn(A) -> R, A) -> R, { fn call<A, R, F>(f: &F, a: A) -> R where F: Fn(&dyn Fn(A) -> R, A) -> R, { f(&|a| call(f, a), a) } move |a| call(&f, a) } // ---------- end recurse ---------- // ---------- 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<const M: u32>(u32); impl<const M: u32> 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<const M: u32> 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<const M: u32> 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<const M: u32> Mul for ModInt<{ M }> { type Output = Self; fn mul(self, rhs: Self) -> Self::Output { self.const_mul(rhs) } } impl<const M: u32> Div for ModInt<{ M }> { type Output = Self; fn div(self, rhs: Self) -> Self::Output { self * rhs.inv() } } impl<const M: u32> AddAssign for ModInt<{ M }> { fn add_assign(&mut self, rhs: Self) { *self = *self + rhs; } } impl<const M: u32> SubAssign for ModInt<{ M }> { fn sub_assign(&mut self, rhs: Self) { *self = *self - rhs; } } impl<const M: u32> MulAssign for ModInt<{ M }> { fn mul_assign(&mut self, rhs: Self) { *self = *self * rhs; } } impl<const M: u32> DivAssign for ModInt<{ M }> { fn div_assign(&mut self, rhs: Self) { *self = *self / rhs; } } impl<const M: u32> Neg for ModInt<{ M }> { type Output = Self; fn neg(self) -> Self::Output { if self.0 == 0 { self } else { Self(M - self.0) } } } impl<const M: u32> std::fmt::Display for ModInt<{ M }> { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { write!(f, "{}", self.get()) } } impl<const M: u32> std::fmt::Debug for ModInt<{ M }> { fn fmt<'a>(&self, f: &mut std::fmt::Formatter<'a>) -> std::fmt::Result { write!(f, "{}", self.get()) } } impl<const M: u32> std::str::FromStr for ModInt<{ M }> { type Err = std::num::ParseIntError; fn from_str(s: &str) -> Result<Self, Self::Err> { let val = s.parse::<u32>()?; Ok(ModInt::new(val)) } } impl<const M: u32> From<usize> for ModInt<{ M }> { fn from(val: usize) -> ModInt<{ M }> { ModInt::new((val % M as usize) as u32) } } // ---------- end modint ---------- // ---------- begin precalc ---------- pub struct Precalc<const MOD: u32> { fact: Vec<ModInt<MOD>>, ifact: Vec<ModInt<MOD>>, inv: Vec<ModInt<MOD>>, } impl<const MOD: u32> Precalc<MOD> { 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<MOD> { self.fact[n] } pub fn ifact(&self, n: usize) -> ModInt<MOD> { self.ifact[n] } pub fn inv(&self, n: usize) -> ModInt<MOD> { assert!(0 < n); self.inv[n] } pub fn perm(&self, n: usize, k: usize) -> ModInt<MOD> { if k > n { return ModInt::zero(); } self.fact[n] * self.ifact[n - k] } pub fn binom(&self, n: usize, k: usize) -> ModInt<MOD> { if n < k { return ModInt::zero(); } self.fact[n] * self.ifact[k] * self.ifact[n - k] } } // ---------- end precalc ---------- impl<const M: u32> Zero for ModInt<{ M }> { fn zero() -> Self { Self::zero() } fn is_zero(&self) -> bool { self.0 == 0 } } impl<const M: u32> One for ModInt<{ M }> { fn one() -> Self { Self::one() } fn is_one(&self) -> bool { self.get() == 1 } } // ---------- begin array op ---------- struct NTTPrecalc<const M: u32> { sum_e: [ModInt<{ M }>; 30], sum_ie: [ModInt<{ M }>; 30], } impl<const M: u32> NTTPrecalc<{ M }> { const fn new() -> Self { let cnt2 = (M - 1).trailing_zeros() as usize; let root = ModInt::new(ModInt::<{ M }>::PRIMITIVE_ROOT); let zeta = root.pow((M - 1) as u64 >> cnt2); let mut es = [ModInt::zero(); 30]; let mut ies = [ModInt::zero(); 30]; let mut sum_e = [ModInt::zero(); 30]; let mut sum_ie = [ModInt::zero(); 30]; let mut e = zeta; let mut ie = e.inv(); let mut i = cnt2; while i >= 2 { es[i - 2] = e; ies[i - 2] = ie; e = e.const_mul(e); ie = ie.const_mul(ie); i -= 1; } let mut now = ModInt::one(); let mut inow = ModInt::one(); let mut i = 0; while i < cnt2 - 1 { sum_e[i] = es[i].const_mul(now); sum_ie[i] = ies[i].const_mul(inow); now = ies[i].const_mul(now); inow = es[i].const_mul(inow); i += 1; } Self { sum_e, sum_ie } } } struct NTTPrecalcHelper<const MOD: u32>; impl<const MOD: u32> NTTPrecalcHelper<MOD> { const A: NTTPrecalc<MOD> = NTTPrecalc::new(); } pub trait ArrayAdd { type Item; fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item>; } impl<T> ArrayAdd for [T] where T: Zero + Copy, { type Item = T; fn add(&self, rhs: &[Self::Item]) -> Vec<Self::Item> { let mut c = vec![T::zero(); self.len().max(rhs.len())]; c[..self.len()].copy_from_slice(self); c.add_assign(rhs); c } } pub trait ArrayAddAssign { type Item; fn add_assign(&mut self, rhs: &[Self::Item]); } impl<T> ArrayAddAssign for [T] where T: Add<Output = T> + Copy, { type Item = T; fn add_assign(&mut self, rhs: &[Self::Item]) { assert!(self.len() >= rhs.len()); self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x + *a); } } impl<T> ArrayAddAssign for Vec<T> where T: Zero + Add<Output = T> + Copy, { type Item = T; fn add_assign(&mut self, rhs: &[Self::Item]) { if self.len() < rhs.len() { self.resize(rhs.len(), T::zero()); } self.as_mut_slice().add_assign(rhs); } } pub trait ArraySub { type Item; fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item>; } impl<T> ArraySub for [T] where T: Zero + Sub<Output = T> + Copy, { type Item = T; fn sub(&self, rhs: &[Self::Item]) -> Vec<Self::Item> { let mut c = vec![T::zero(); self.len().max(rhs.len())]; c[..self.len()].copy_from_slice(self); c.sub_assign(rhs); c } } pub trait ArraySubAssign { type Item; fn sub_assign(&mut self, rhs: &[Self::Item]); } impl<T> ArraySubAssign for [T] where T: Sub<Output = T> + Copy, { type Item = T; fn sub_assign(&mut self, rhs: &[Self::Item]) { assert!(self.len() >= rhs.len()); self.iter_mut().zip(rhs).for_each(|(x, a)| *x = *x - *a); } } impl<T> ArraySubAssign for Vec<T> where T: Zero + Sub<Output = T> + Copy, { type Item = T; fn sub_assign(&mut self, rhs: &[Self::Item]) { if self.len() < rhs.len() { self.resize(rhs.len(), T::zero()); } self.as_mut_slice().sub_assign(rhs); } } pub trait ArrayDot { type Item; fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item>; } impl<T> ArrayDot for [T] where T: Mul<Output = T> + Copy, { type Item = T; fn dot(&self, rhs: &[Self::Item]) -> Vec<Self::Item> { assert!(self.len() == rhs.len()); self.iter().zip(rhs).map(|p| *p.0 * *p.1).collect() } } pub trait ArrayDotAssign { type Item; fn dot_assign(&mut self, rhs: &[Self::Item]); } impl<T> ArrayDotAssign for [T] where T: MulAssign + Copy, { type Item = T; fn dot_assign(&mut self, rhs: &[Self::Item]) { assert!(self.len() == rhs.len()); self.iter_mut().zip(rhs).for_each(|(x, a)| *x *= *a); } } pub trait ArrayMul { type Item; fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item>; } impl<T> ArrayMul for [T] where T: Zero + One + Copy, { type Item = T; fn mul(&self, rhs: &[Self::Item]) -> Vec<Self::Item> { if self.is_empty() || rhs.is_empty() { return vec![]; } let mut res = vec![T::zero(); self.len() + rhs.len() - 1]; for (i, a) in self.iter().enumerate() { for (res, b) in res[i..].iter_mut().zip(rhs.iter()) { *res = *res + *a * *b; } } res } } // transform でlen=1を指定すればNTTになる pub trait ArrayConvolution { type Item; fn transform(&mut self, len: usize); fn inverse_transform(&mut self, len: usize); fn convolution(&self, rhs: &[Self::Item]) -> Vec<Self::Item>; } impl<const M: u32> ArrayConvolution for [ModInt<{ M }>] { type Item = ModInt<{ M }>; fn transform(&mut self, len: usize) { let f = self; let n = f.len(); let k = (n / len).trailing_zeros() as usize; assert!(len << k == n); assert!(k <= ModInt::<{ M }>::ORDER); let pre = &NTTPrecalcHelper::<{ M }>::A; for ph in 1..=k { let p = len << (k - ph); let mut now = ModInt::one(); for (i, f) in f.chunks_exact_mut(2 * p).enumerate() { let (x, y) = f.split_at_mut(p); for (x, y) in x.iter_mut().zip(y.iter_mut()) { let l = *x; let r = *y * now; *x = l + r; *y = l - r; } now *= pre.sum_e[(!i).trailing_zeros() as usize]; } } } fn inverse_transform(&mut self, len: usize) { let f = self; let n = f.len(); let k = (n / len).trailing_zeros() as usize; assert!(len << k == n); assert!(k <= ModInt::<{ M }>::ORDER); let pre = &NTTPrecalcHelper::<{ M }>::A; for ph in (1..=k).rev() { let p = len << (k - ph); let mut inow = ModInt::one(); for (i, f) in f.chunks_exact_mut(2 * p).enumerate() { let (x, y) = f.split_at_mut(p); for (x, y) in x.iter_mut().zip(y.iter_mut()) { let l = *x; let r = *y; *x = l + r; *y = (l - r) * inow; } inow *= pre.sum_ie[(!i).trailing_zeros() as usize]; } } let ik = ModInt::new(2).inv().pow(k as u64); for f in f.iter_mut() { *f *= ik; } } fn convolution(&self, rhs: &[Self::Item]) -> Vec<Self::Item> { if self.len().min(rhs.len()) <= 32 { return self.mul(rhs); } const PARAM: usize = 10; let size = self.len() + rhs.len() - 1; let mut k = 0; while (size + (1 << k) - 1) >> k > PARAM { k += 1; } let len = (size + (1 << k) - 1) >> k; let mut f = vec![ModInt::zero(); len << k]; let mut g = vec![ModInt::zero(); len << k]; f[..self.len()].copy_from_slice(self); g[..rhs.len()].copy_from_slice(rhs); f.transform(len); g.transform(len); let mut buf = [ModInt::zero(); 2 * PARAM - 1]; let buf = &mut buf[..(2 * len - 1)]; let pre = &NTTPrecalcHelper::<{ M }>::A; let mut now = ModInt::one(); for (i, (f, g)) in f .chunks_exact_mut(2 * len) .zip(g.chunks_exact(2 * len)) .enumerate() { let mut r = now; for (f, g) in f.chunks_exact_mut(len).zip(g.chunks_exact(len)) { buf.fill(ModInt::zero()); for (i, f) in f.iter().enumerate() { for (buf, g) in buf[i..].iter_mut().zip(g.iter()) { *buf = *buf + *f * *g; } } f.copy_from_slice(&buf[..len]); for (f, buf) in f.iter_mut().zip(buf[len..].iter()) { *f = *f + r * *buf; } r = -r; } now *= pre.sum_e[(!i).trailing_zeros() as usize]; } f.inverse_transform(len); f.truncate(self.len() + rhs.len() - 1); f } } // ---------- end array op ---------- // ---------- begin trait ---------- use std::ops::*; pub trait Zero: Sized + Add<Self, Output = Self> { fn zero() -> Self; fn is_zero(&self) -> bool; } pub trait One: Sized + Mul<Self, Output = Self> { fn one() -> Self; fn is_one(&self) -> bool; } pub trait Group: Zero + Sub<Output = Self> + Neg<Output = Self> {} pub trait SemiRing: Zero + One {} pub trait Ring: SemiRing + Group {} pub trait Field: Ring + Div<Output = Self> {} impl<T> Group for T where T: Zero + Sub<Output = Self> + Neg<Output = Self> {} impl<T> SemiRing for T where T: Zero + One {} impl<T> Ring for T where T: SemiRing + Group {} impl<T> Field for T where T: Ring + Div<Output = Self> {} pub fn zero<T: Zero>() -> T { T::zero() } pub fn one<T: One>() -> T { T::one() } pub fn pow<T: One + Clone>(mut r: T, mut n: usize) -> T { let mut t = one(); while n > 0 { if n & 1 == 1 { t = t * r.clone(); } r = r.clone() * r; n >>= 1; } t } pub fn pow_sum<T: SemiRing + Clone>(r: T, n: usize) -> T { if n == 0 { T::zero() } else if n & 1 == 1 { T::one() + r.clone() * pow_sum(r, n - 1) } else { let a = T::one() + r.clone(); let b = r.clone() * r; a * pow_sum(b, n / 2) } } // ---------- end trait ---------- // ---------- begin CSR ---------- pub struct CSR { size: usize, pos: Vec<u32>, list: Vec<u32>, } impl CSR { pub fn new<I>(size: usize, it: I) -> Self where I: Iterator<Item = (usize, usize)> + Clone, { let mut pos = vec![0; size + 1]; for (s, t) in it.clone() { assert!(s < size && t < size); pos[s + 1] += 1; } for i in 1..=size { pos[i] += pos[i - 1]; } let mut x = pos[..size].to_vec(); let mut list = vec![0; pos[size] as usize]; for (s, t) in it { let x = &mut x[s]; list[*x as usize] = t as u32; *x += 1; } CSR { size, pos, list } } pub fn list(&self, v: usize) -> impl Iterator<Item = usize> + '_ { assert!(v < self.size); let s = self.pos[v] as usize; let t = self.pos[v + 1] as usize; self.list[s..t].iter().map(|p| *p as usize) } } // ---------- end CSR ---------- // ---------- begin sparse table ---------- pub struct SparseTable<T, F> { table: Vec<Vec<T>>, size: usize, op: F, } impl<T, F> SparseTable<T, F> where F: Fn(&T, &T) -> T { pub fn new(mut a: Vec<T>, op: F) -> Self { assert!(a.len() > 0); let size = a.len(); let mut table = vec![]; let mut w = 1; while w + 1 <= a.len() { let next = a.windows(w + 1).map(|a| op(&a[0], &a[w])).collect::<Vec<_>>(); table.push(a); a = next; w <<= 1; } table.push(a); SparseTable { table: table, size: size, op: op, } } pub fn find(&self, l: usize, r: usize) -> T { assert!(l < r && r <= self.size); let k = (r - l + 1).next_power_of_two().trailing_zeros() as usize - 1; let table = &self.table[k]; (self.op)(&table[l], &table[r - (1 << k)]) } } // ---------- end sparse table ---------- // ---------- begin chmin, chmax ---------- pub trait ChangeMinMax { fn chmin(&mut self, x: Self) -> bool; fn chmax(&mut self, x: Self) -> bool; } impl<T: PartialOrd> ChangeMinMax for T { fn chmin(&mut self, x: Self) -> bool { *self > x && { *self = x; true } } fn chmax(&mut self, x: Self) -> bool { *self < x && { *self = x; true } } } // ---------- end chmin, chmax ----------