-
Notifications
You must be signed in to change notification settings - Fork 5
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
1 changed file
with
367 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,367 @@ | ||
use std::cmp::*; | ||
// https://qiita.com/tanakh/items/0ba42c7ca36cd29d0ac8 | ||
macro_rules! input { | ||
($($r:tt)*) => { | ||
let stdin = std::io::stdin(); | ||
let mut bytes = std::io::Read::bytes(std::io::BufReader::new(stdin.lock())); | ||
let mut next = move || -> String{ | ||
bytes.by_ref().map(|r|r.unwrap() as char) | ||
.skip_while(|c|c.is_whitespace()) | ||
.take_while(|c|!c.is_whitespace()) | ||
.collect() | ||
}; | ||
input_inner!{next, $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! input_inner { | ||
($next:expr) => {}; | ||
($next:expr,) => {}; | ||
($next:expr, $var:ident : $t:tt $($r:tt)*) => { | ||
let $var = read_value!($next, $t); | ||
input_inner!{$next $($r)*} | ||
}; | ||
} | ||
|
||
macro_rules! read_value { | ||
($next:expr, [ $t:tt ; $len:expr ]) => { | ||
(0..$len).map(|_| read_value!($next, $t)).collect::<Vec<_>>() | ||
}; | ||
($next:expr, $t:ty) => ($next().parse::<$t>().expect("Parse error")); | ||
} | ||
|
||
/// Verified by https://atcoder.jp/contests/abc198/submissions/21774342 | ||
mod mod_int { | ||
use std::ops::*; | ||
pub trait Mod: Copy { fn m() -> i64; } | ||
#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord)] | ||
pub struct ModInt<M> { pub x: i64, phantom: ::std::marker::PhantomData<M> } | ||
impl<M: Mod> ModInt<M> { | ||
// x >= 0 | ||
pub fn new(x: i64) -> Self { ModInt::new_internal(x % M::m()) } | ||
fn new_internal(x: i64) -> Self { | ||
ModInt { x: x, phantom: ::std::marker::PhantomData } | ||
} | ||
pub fn pow(self, mut e: i64) -> Self { | ||
debug_assert!(e >= 0); | ||
let mut sum = ModInt::new_internal(1); | ||
let mut cur = self; | ||
while e > 0 { | ||
if e % 2 != 0 { sum *= cur; } | ||
cur *= cur; | ||
e /= 2; | ||
} | ||
sum | ||
} | ||
#[allow(dead_code)] | ||
pub fn inv(self) -> Self { self.pow(M::m() - 2) } | ||
} | ||
impl<M: Mod> Default for ModInt<M> { | ||
fn default() -> Self { Self::new_internal(0) } | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> Add<T> for ModInt<M> { | ||
type Output = Self; | ||
fn add(self, other: T) -> Self { | ||
let other = other.into(); | ||
let mut sum = self.x + other.x; | ||
if sum >= M::m() { sum -= M::m(); } | ||
ModInt::new_internal(sum) | ||
} | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> Sub<T> for ModInt<M> { | ||
type Output = Self; | ||
fn sub(self, other: T) -> Self { | ||
let other = other.into(); | ||
let mut sum = self.x - other.x; | ||
if sum < 0 { sum += M::m(); } | ||
ModInt::new_internal(sum) | ||
} | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> Mul<T> for ModInt<M> { | ||
type Output = Self; | ||
fn mul(self, other: T) -> Self { ModInt::new(self.x * other.into().x % M::m()) } | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> AddAssign<T> for ModInt<M> { | ||
fn add_assign(&mut self, other: T) { *self = *self + other; } | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> SubAssign<T> for ModInt<M> { | ||
fn sub_assign(&mut self, other: T) { *self = *self - other; } | ||
} | ||
impl<M: Mod, T: Into<ModInt<M>>> MulAssign<T> for ModInt<M> { | ||
fn mul_assign(&mut self, other: T) { *self = *self * other; } | ||
} | ||
impl<M: Mod> Neg for ModInt<M> { | ||
type Output = Self; | ||
fn neg(self) -> Self { ModInt::new(0) - self } | ||
} | ||
impl<M> ::std::fmt::Display for ModInt<M> { | ||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||
self.x.fmt(f) | ||
} | ||
} | ||
impl<M: Mod> ::std::fmt::Debug for ModInt<M> { | ||
fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { | ||
let (mut a, mut b, _) = red(self.x, M::m()); | ||
if b < 0 { | ||
a = -a; | ||
b = -b; | ||
} | ||
write!(f, "{}/{}", a, b) | ||
} | ||
} | ||
impl<M: Mod> From<i64> for ModInt<M> { | ||
fn from(x: i64) -> Self { Self::new(x) } | ||
} | ||
// Finds the simplest fraction x/y congruent to r mod p. | ||
// The return value (x, y, z) satisfies x = y * r + z * p. | ||
fn red(r: i64, p: i64) -> (i64, i64, i64) { | ||
if r.abs() <= 10000 { | ||
return (r, 1, 0); | ||
} | ||
let mut nxt_r = p % r; | ||
let mut q = p / r; | ||
if 2 * nxt_r >= r { | ||
nxt_r -= r; | ||
q += 1; | ||
} | ||
if 2 * nxt_r <= -r { | ||
nxt_r += r; | ||
q -= 1; | ||
} | ||
let (x, z, y) = red(nxt_r, r); | ||
(x, y - q * z, z) | ||
} | ||
} // mod mod_int | ||
|
||
macro_rules! define_mod { | ||
($struct_name: ident, $modulo: expr) => { | ||
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] | ||
pub struct $struct_name {} | ||
impl mod_int::Mod for $struct_name { fn m() -> i64 { $modulo } } | ||
} | ||
} | ||
const MOD: i64 = 998_244_353; | ||
define_mod!(P, MOD); | ||
type MInt = mod_int::ModInt<P>; | ||
|
||
// Depends on MInt.rs | ||
fn fact_init(w: usize) -> (Vec<MInt>, Vec<MInt>) { | ||
let mut fac = vec![MInt::new(1); w]; | ||
let mut invfac = vec![0.into(); w]; | ||
for i in 1..w { | ||
fac[i] = fac[i - 1] * i as i64; | ||
} | ||
invfac[w - 1] = fac[w - 1].inv(); | ||
for i in (0..w - 1).rev() { | ||
invfac[i] = invfac[i + 1] * (i as i64 + 1); | ||
} | ||
(fac, invfac) | ||
} | ||
|
||
// FFT (in-place, verified as NTT only) | ||
// R: Ring + Copy | ||
// Verified by: https://judge.yosupo.jp/submission/53831 | ||
// Adopts the technique used in https://judge.yosupo.jp/submission/3153. | ||
mod fft { | ||
use std::ops::*; | ||
// n should be a power of 2. zeta is a primitive n-th root of unity. | ||
// one is unity | ||
// Note that the result is bit-reversed. | ||
pub fn fft<R>(f: &mut [R], zeta: R, one: R) | ||
where R: Copy + | ||
Add<Output = R> + | ||
Sub<Output = R> + | ||
Mul<Output = R> { | ||
let n = f.len(); | ||
assert!(n.is_power_of_two()); | ||
let mut m = n; | ||
let mut base = zeta; | ||
unsafe { | ||
while m > 2 { | ||
m >>= 1; | ||
let mut r = 0; | ||
while r < n { | ||
let mut w = one; | ||
for s in r..r + m { | ||
let &u = f.get_unchecked(s); | ||
let d = *f.get_unchecked(s + m); | ||
*f.get_unchecked_mut(s) = u + d; | ||
*f.get_unchecked_mut(s + m) = w * (u - d); | ||
w = w * base; | ||
} | ||
r += 2 * m; | ||
} | ||
base = base * base; | ||
} | ||
if m > 1 { | ||
// m = 1 | ||
let mut r = 0; | ||
while r < n { | ||
let &u = f.get_unchecked(r); | ||
let d = *f.get_unchecked(r + 1); | ||
*f.get_unchecked_mut(r) = u + d; | ||
*f.get_unchecked_mut(r + 1) = u - d; | ||
r += 2; | ||
} | ||
} | ||
} | ||
} | ||
pub fn inv_fft<R>(f: &mut [R], zeta_inv: R, one: R) | ||
where R: Copy + | ||
Add<Output = R> + | ||
Sub<Output = R> + | ||
Mul<Output = R> { | ||
let n = f.len(); | ||
assert!(n.is_power_of_two()); | ||
let zeta = zeta_inv; // inverse FFT | ||
let mut zetapow = Vec::with_capacity(20); | ||
{ | ||
let mut m = 1; | ||
let mut cur = zeta; | ||
while m < n { | ||
zetapow.push(cur); | ||
cur = cur * cur; | ||
m *= 2; | ||
} | ||
} | ||
let mut m = 1; | ||
unsafe { | ||
if m < n { | ||
zetapow.pop(); | ||
let mut r = 0; | ||
while r < n { | ||
let &u = f.get_unchecked(r); | ||
let d = *f.get_unchecked(r + 1); | ||
*f.get_unchecked_mut(r) = u + d; | ||
*f.get_unchecked_mut(r + 1) = u - d; | ||
r += 2; | ||
} | ||
m = 2; | ||
} | ||
while m < n { | ||
let base = zetapow.pop().unwrap(); | ||
let mut r = 0; | ||
while r < n { | ||
let mut w = one; | ||
for s in r..r + m { | ||
let &u = f.get_unchecked(s); | ||
let d = *f.get_unchecked(s + m) * w; | ||
*f.get_unchecked_mut(s) = u + d; | ||
*f.get_unchecked_mut(s + m) = u - d; | ||
w = w * base; | ||
} | ||
r += 2 * m; | ||
} | ||
m *= 2; | ||
} | ||
} | ||
} | ||
} | ||
|
||
// Depends on: fft.rs, MInt.rs | ||
// Verified by: ABC269-Ex (https://atcoder.jp/contests/abc269/submissions/39116328) | ||
pub struct FPSOps<M: mod_int::Mod> { | ||
gen: mod_int::ModInt<M>, | ||
} | ||
|
||
impl<M: mod_int::Mod> FPSOps<M> { | ||
pub fn new(gen: mod_int::ModInt<M>) -> Self { | ||
FPSOps { gen: gen } | ||
} | ||
} | ||
|
||
impl<M: mod_int::Mod> FPSOps<M> { | ||
pub fn add(&self, mut a: Vec<mod_int::ModInt<M>>, mut b: Vec<mod_int::ModInt<M>>) -> Vec<mod_int::ModInt<M>> { | ||
if a.len() < b.len() { | ||
std::mem::swap(&mut a, &mut b); | ||
} | ||
for i in 0..b.len() { | ||
a[i] += b[i]; | ||
} | ||
a | ||
} | ||
pub fn mul(&self, a: Vec<mod_int::ModInt<M>>, b: Vec<mod_int::ModInt<M>>) -> Vec<mod_int::ModInt<M>> { | ||
type MInt<M> = mod_int::ModInt<M>; | ||
let n = a.len() - 1; | ||
let m = b.len() - 1; | ||
let mut p = 1; | ||
while p <= n + m { p *= 2; } | ||
let mut f = vec![MInt::new(0); p]; | ||
let mut g = vec![MInt::new(0); p]; | ||
for i in 0..n + 1 { f[i] = a[i]; } | ||
for i in 0..m + 1 { g[i] = b[i]; } | ||
let fac = MInt::new(p as i64).inv(); | ||
let zeta = self.gen.pow((M::m() - 1) / p as i64); | ||
fft::fft(&mut f, zeta, 1.into()); | ||
fft::fft(&mut g, zeta, 1.into()); | ||
for i in 0..p { f[i] *= g[i] * fac; } | ||
fft::inv_fft(&mut f, zeta.inv(), 1.into()); | ||
f.truncate(n + m + 1); | ||
f | ||
} | ||
} | ||
|
||
// https://yukicoder.me/problems/no/2484 (3.5) | ||
// https://yukicoder.me/problems/no/2485 (3.5) | ||
// 操作をそれぞれ S, T_{k+1}, U_{k+1}, V と名付ける。T_k U_{k+1} と SV は同じ結果をもたらすが、それ以外はほとんど自由度がなく 1 通りに定まる。 | ||
// c[i] = B[i+1]-B[i] (i >= 1), c[0] = B[1] とすると、各操作は以下のようになる: | ||
// S: なにもしない | ||
// T_{k+1}: 0 番目を +1, k+1 番目を -1 する (0 <= k <= N-2) | ||
// U_{k+1}: k 番目を +1 する (1 <= k <= N-1) | ||
// V: 0 番目を +1 する | ||
// 最終的にすべてゼロの配列を操作によって c と等しくできればよい。 | ||
// c[0] + sum_{i>=1} min(c[i], 0) < 0 であれば不可能なので 0 通り。 | ||
// そうでないとき、T_? と U_? の必須回数、および追加で必要な V の回数は簡単に求められる。 | ||
// V を何個 T_1 U_2, T_2 U_3, T_3 U_4 にするかを全探索すれば、それぞれに対して組み合わせの和を計算すれば良い。 | ||
// これは畳み込みでできる。 | ||
fn main() { | ||
input! { | ||
n: usize, m: usize, | ||
b: [i64; n], | ||
} | ||
let (fac, invfac) = fact_init(m + 1); | ||
let mut c = vec![0; n]; | ||
c[0] = b[0]; | ||
for i in 1..n { | ||
c[i] = b[i] - b[i - 1]; | ||
} | ||
let mut negsum = 0; | ||
let mut possum = 0; | ||
for i in 1..n { | ||
negsum += min(0, c[i]); | ||
possum += max(0, c[i]); | ||
} | ||
if negsum + c[0] < 0 { | ||
println!("0"); | ||
return; | ||
} | ||
// Rules out e.g. m m-1 m | ||
if possum + c[0] > m as i64 { | ||
println!("0"); | ||
return; | ||
} | ||
let rest = m - (possum + c[0]) as usize; | ||
let t = (c[0] + negsum) as usize; | ||
let mut prod = vec![MInt::new(1)]; | ||
let fps = FPSOps::new(MInt::new(3)); | ||
for i in 1..n { | ||
let mut a = vec![MInt::new(0); m + 1]; | ||
let x = c[i].abs() as usize; | ||
for j in 0..m + 1 { | ||
if 2 * j + x <= m { | ||
a[2 * j + x] += invfac[j + x] * invfac[j]; | ||
} | ||
} | ||
prod = fps.mul(prod, a); | ||
prod.truncate(m + 1); | ||
} | ||
let mut a = vec![MInt::new(0); m + 1]; | ||
for j in 0..min(t, rest) + 1 { | ||
if t - j + rest - j <= m { | ||
a[t - j + rest - j] += invfac[t - j] * invfac[rest - j]; | ||
} | ||
} | ||
prod = fps.mul(prod, a); | ||
prod.truncate(m + 1); | ||
println!("{}", prod[m] * fac[m]); | ||
} |