haar_lib/math/fps/
pow_sparse.rs1use crate::math::polynomial::sparse::SparsePolynomial;
3use crate::math::polynomial::Polynomial;
4use crate::math::prime_mod::PrimeMod;
5use crate::num::const_modint::*;
6
7pub trait FpsPowSparse {
9 type Output;
11
12 fn fps_pow_sparse(self, m: u64, n: usize) -> Result<Self::Output, &'static str>;
14}
15
16impl<P: PrimeMod> FpsPowSparse for SparsePolynomial<P> {
17 type Output = Polynomial<P>;
18
19 fn fps_pow_sparse(self, m: u64, n: usize) -> Result<Self::Output, &'static str> {
21 if m == 0 {
22 let mut f: Vec<_> = vec![ConstModInt::new(0); n];
23 f[0] = ConstModInt::new(1);
24 return Ok(f.into());
25 }
26
27 let k = (0..n).find(|&i| self.coeff_of(i).value() != 0).unwrap_or(n);
28
29 if k >= n {
30 return Ok(vec![ConstModInt::new(0); n].into());
31 }
32
33 if k.checked_mul(m as usize).is_none_or(|x| x >= n) {
34 return Ok(vec![ConstModInt::new(0); n].into());
35 }
36
37 let a = self.coeff_of(k);
38
39 let mut f = self;
40 f.shift_lower(k);
41 f.scale(a.inv());
42
43 let mut g = vec![ConstModInt::new(0); n];
44 let mut ret = vec![ConstModInt::new(0); n];
45 ret[0] = 1.into();
46
47 let mut invs = vec![ConstModInt::new(1); n + 1];
48 for i in 2..=n {
49 invs[i] = -invs[P::PRIME_NUM as usize % i] * ConstModInt::new(P::PRIME_NUM / i as u32);
50 }
51
52 for i in 0..n - 1 {
53 let mut s = ConstModInt::new(0);
54
55 for (&j, &fj) in f.iter() {
56 if j != 0 {
57 if i >= j {
58 s -= fj * g[i - j];
59 }
60 if i + 1 >= j {
61 s += ret[i - j + 1] * j.into() * fj * m.into();
62 }
63 }
64 }
65
66 g[i] = s;
67 ret[i + 1] = s * invs[i + 1];
68 }
69
70 let mut ret = Polynomial::from(ret);
71 ret.scale(a.pow(m));
72 ret.shift_higher(m as usize * k);
73 Ok(ret)
74 }
75}