use galois_field::GaloisField; use proconio::{input, marker::Usize1}; const MOD: u64 = 998_244_353; fn main() { input! { n: Usize1, t: usize, k: u64, l: u64, } let mut dp = vec![gf!(1)]; for i in 1..t { let mut next = gf!(0); if i >= 1 { next += gf!(k - 1) / gf!(6) * dp[i - 1]; } if i >= 2 { next += gf!(l - k) / gf!(6) * dp[i - 2]; } if i >= t { next += gf!(7 - l) / gf!(6) * dp[i - t]; } dp.push(next); } assert_eq!(dp.len(), t); if n <= t { println!("{}", dp[n].value()); return; } let mut x = vec![vec![gf!(0); t]; t]; x[0][0] = gf!(k - 1) / gf!(6); x[0][1] = gf!(l - k) / gf!(6); x[0][t - 1] = gf!(7 - l) / gf!(6); for i in 1..t { x[i][i - 1] = gf!(1); } let coef = pow(&x, n); let ans = coef .last() .unwrap() .iter() .zip(dp.iter().rev()) .map(|(coef, dp)| coef * dp) .sum::>(); println!("{}", ans.value()); } fn multiple( a: &Vec>>, b: &Vec>>, ) -> Vec>> { let n = a.len(); let mut res = vec![vec![gf!(0); n]; n]; for i in 0..n { for j in 0..n { for k in 0..n { res[i][j] += a[i][k] * b[k][j]; } } } res } fn pow(a: &Vec>>, mut n: usize) -> Vec>> { let m = a.len(); let mut res = vec![vec![gf!(0); m]; m]; for i in 0..m { res[i][i] = gf!(1); } let mut base = a.clone(); while n > 0 { if n & 1 == 1 { res = multiple(&res, &base); } base = multiple(&base, &base); n /= 2; } res } pub mod galois_field { use std::{ iter::{Product, Sum}, ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign}, }; #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct GaloisField { value: u64, } impl GaloisField { pub fn new(value: u64) -> Self { Self { value: value % MOD } } pub fn value(&self) -> u64 { self.value } pub fn pow(&self, mut exp: u64) -> Self { let mut res = Self::new(1); let mut base = self.clone(); while exp > 0 { if exp & 1 == 1 { res *= base; } base *= base; exp >>= 1; } res } pub fn inv(&self) -> Self { self.pow(MOD - 2) } } macro_rules! impl_from_signed { ($($t:ty),*) => { $( impl From<$t> for GaloisField { fn from(x: $t) -> Self { if x < 0 { - Self::new((MOD as i64 - x as i64) as u64) } else { Self::new(x as u64) } } } )* }; } macro_rules! impl_from_unsigned { ($($t:ty),*) => { $( impl From<$t> for GaloisField { fn from(x: $t) -> Self { Self::new(x as u64) } } )* }; } impl_from_signed!(i8, i16, i32, i64, i128, isize); impl_from_unsigned!(u8, u16, u32, u64, u128, usize); #[macro_export] macro_rules! gf { ($value:expr) => { $crate::GaloisField::from($value) }; ($value:expr; mod $p:expr) => { $crate::GaloisField::<$p>::from($value) }; } impl AddAssign> for GaloisField { fn add_assign(&mut self, rhs: GaloisField) { self.value += rhs.value; if self.value >= MOD { self.value -= MOD; } } } impl SubAssign> for GaloisField { fn sub_assign(&mut self, rhs: GaloisField) { if self.value < rhs.value { self.value += MOD; } self.value -= rhs.value; } } impl MulAssign> for GaloisField { fn mul_assign(&mut self, rhs: GaloisField) { self.value *= rhs.value; self.value %= MOD; } } impl DivAssign> for GaloisField { fn div_assign(&mut self, rhs: GaloisField) { self.value *= rhs.inv().value; self.value %= MOD; } } macro_rules! gf_forward_ops { ($( $trait:ident, $trait_assign:ident, $fn:ident, $fn_assign:ident, )*) => {$( impl $trait_assign<&GaloisField> for GaloisField { fn $fn_assign(&mut self, rhs: &GaloisField) { self.$fn_assign(*rhs); } } impl>> $trait for GaloisField { type Output = GaloisField; fn $fn(mut self, rhs: T) -> Self::Output { self.$fn_assign(rhs.into()); self } } impl $trait<&GaloisField> for GaloisField { type Output = GaloisField; fn $fn(self, rhs: &GaloisField) -> Self::Output { self.$fn(*rhs) } } impl>> $trait for &GaloisField { type Output = GaloisField; fn $fn(self, rhs: T) -> Self::Output { (*self).$fn(rhs.into()) } } impl $trait<&GaloisField> for &GaloisField { type Output = GaloisField; fn $fn(self, rhs: &GaloisField) -> Self::Output { (*self).$fn(*rhs) } } )*}; } gf_forward_ops! { Add, AddAssign, add, add_assign, Sub, SubAssign, sub, sub_assign, Mul, MulAssign, mul, mul_assign, Div, DivAssign, div, div_assign, } impl Neg for GaloisField { type Output = Self; fn neg(mut self) -> Self::Output { if self.value > 0 { self.value = MOD - self.value; } self } } impl Sum for GaloisField { fn sum>(iter: I) -> Self { iter.fold(Self::new(0), |acc, x| acc + x) } } impl<'a, const MOD: u64> Sum<&'a Self> for GaloisField { fn sum>(iter: I) -> Self { iter.copied().sum() } } impl Product for GaloisField { fn product>(iter: I) -> Self { iter.fold(Self::new(1), |acc, x| acc * x) } } impl<'a, const MOD: u64> Product<&'a Self> for GaloisField { fn product>(iter: I) -> Self { iter.copied().product() } } }