haar_lib/math/combinatorics/
stirling_first.rs1use crate::math::convolution::ntt::NTT;
5use crate::math::polynomial::{polynomial_taylor_shift::*, Polynomial};
6use crate::math::prime_mod::PrimeMod;
7use crate::num::const_modint::*;
8
9pub fn stirling_first<P: PrimeMod>(n: usize) -> Vec<ConstModInt<P>> {
13 let ff = ConstModIntBuilder::new();
14
15 let mut ret = Polynomial::<P>::from(vec![1]);
16 let ntt = NTT::<P>::new();
17
18 let mut t: usize = 0;
19 let mut check = false;
20
21 for i in (0..usize::BITS).rev() {
22 if check {
23 let s = ret.clone().taylor_shift(-ff.from_u64(t as u64));
24 ret = ntt.convolve(ret.into(), s.into()).into();
25 ret.as_mut().truncate(t * 2 + 1);
26 t *= 2;
27 }
28
29 if (n & (1 << i)) != 0 {
30 let a = vec![-ff.from_u64(t as u64), ff.from_u64(1)];
31 ret = ntt.convolve(ret.into(), a).into();
32 t += 1;
33
34 check = true;
35 }
36 }
37
38 ret.as_mut().truncate(n + 1);
39 ret.into()
40}
41
42#[cfg(test)]
43mod tests {
44 use crate::math::prime_mod::Prime;
45
46 use super::*;
47
48 type P = Prime<998244353>;
49
50 #[test]
51 fn test() {
52 let ff = ConstModIntBuilder::<P>::new();
53
54 let n = 100;
55 let mut ans = Polynomial::from(vec![ff.from_u64(1)]);
56
57 for i in 1..=n {
58 let res = stirling_first::<P>(i);
59
60 ans *= Polynomial::from(vec![-ff.from_u64(i as u64 - 1), 1.into()]);
61
62 assert_eq!(res, ans.as_ref());
63 }
64 }
65}