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