https://atcoder.jp/contests/abc431/tasks/abc431_f
例えば、Dが1でAをソートした列が1 2 3 4だとすると、1と2の有効列は
1 2 2 1
の2つが考えられますが、これに3を追加するとすると、どちらでも2の左か最後に追加するしかないので、どちらの場合も2通り追加できます。そうすると、4通りのなります。
1 3 2 1 2 3 3 2 1 2 1 3
4を追加するのも同様なので、結局8通りになります。
ただし、Aに同じ数があると少しややしくなります。入力例1だと、ソートして、
1 2 2 5
同じ数はまとめて数だけ数えて、
(1, 1), (2, 2), (5, 1)
となります。まず1に2を2個追加するとき、1があるから3つのマスから2を置くマスを2つ選ぶので、3C2となります。
// Almost Sorted 2 #![allow(non_snake_case)] //////////////////// library //////////////////// fn read<T: std::str::FromStr>() -> T { let mut line = String::new(); std::io::stdin().read_line(&mut line).ok(); line.trim().parse().ok().unwrap() } fn read_vec<T: std::str::FromStr>() -> Vec<T> { read::<String>().split_whitespace() .map(|e| e.parse().ok().unwrap()).collect() } // ax = by + 1 (a, b > 0) fn linear_diophantine(a: i64, b: i64) -> Option<(i64, i64)> { if a == 1 { return Some((1, 0)) } let q = b / a; let r = b % a; if r == 0 { return None } let (x1, y1) = linear_diophantine(r, a)?; Some((-q * x1 - y1, -x1)) } fn inverse<const D: i64>(a: i64) -> i64 { let (x, _y) = linear_diophantine(a, D).unwrap(); x.rem_euclid(D) } //////////////////// CombinationCalculator //////////////////// struct CombinationCalculator<const D: i64> { facts: Vec<i64> } impl<const D: i64> CombinationCalculator<D> { // nCm fn apply(&self, n: i64, m: i64) -> i64 { let num = self.facts[n as usize]; let den = self.facts[m as usize] * self.facts[(n-m) as usize] % D; num * inverse::<D>(den) % D } fn create(N: usize) -> CombinationCalculator::<D> { let mut facts: Vec<i64> = vec![1; N+1]; for n in 1..N+1 { facts[n] = facts[n-1] * (n as i64) % D } CombinationCalculator::<D> { facts } } } //////////////////// process //////////////////// fn read_input() -> (i32, Vec<i32>) { let v: Vec<i32> = read_vec(); let D = v[1]; let A: Vec<i32> = read_vec(); (D, A) } fn groupby(A: &Vec<i32>) -> Vec<(i32, usize)> { let mut v: Vec<(i32, usize)> = vec![]; let mut prev = 0; let mut len = 0; for &a in A.iter() { if len == 0 || a == prev { len += 1 } else { v.push((prev, len)); len = 1 } prev = a } v.push((prev, len)); v } // indexがどこまでさかのぼれるかをVecにする fn calc_back(v: &Vec<(i32, usize)>, D: i32) -> Vec<usize> { let mut w: Vec<usize> = vec![0; v.len()]; let mut k: usize = 0; for i in 0..v.len() { loop { let (a, _) = v[i]; if a <= v[k].0 + D { w[i] = k; break } k += 1 } } w } fn accumulate(v: &Vec<(i32, usize)>) -> Vec<usize> { let mut a: Vec<usize> = vec![0; v.len()+1]; for i in 0..v.len() { a[i+1] = a[i] + v[i].1 } a } const E: usize = 998244353; fn F(D: i32, mut A: Vec<i32>) -> usize { let N = A.len(); let cc = CombinationCalculator::<{E as i64}>::create(N); A.sort(); let v = groupby(&A); let w = calc_back(&v, D); let a = accumulate(&v); let mut n: usize = 1; for i in 0..v.len() { let k = w[i]; let C = cc.apply((a[i+1] - a[k]) as i64, v[i].1 as i64) as usize; n = n * C % E } n } fn main() { let (D, A) = read_input(); println!("{}", F(D, A)) }